Viewing file:
pcp.c (34.89 KB) -rw-rw-rw-Select action/file-type:

(
+) |

(
+) |

(
+) |
Code (
+) |
Session (
+) |

(
+) |
SDB (
+) |

(
+) |

(
+) |

(
+) |

(
+) |

(
+) |
/*
** Copyright 2001-2011 Double Precision, Inc. See COPYING for
** distribution information.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <langinfo.h>
#if HAVE_TERMIOS_H
#include <termios.h>
#endif
#include <fcntl.h>
#include <locale.h>
#include <libintl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <pwd.h>
#include <rfc822/rfc822.h>
#include <rfc822/rfc2047.h>
#include <rfc822/rfc822hdr.h>
#include <rfc2045/rfc2045.h>
#include <rfc2045/rfc2045charset.h>
#include <unicode/unicode.h>
#include <numlib/numlib.h>
#define PCP_ERRMSG(s) gettext(s)
#include "pcp.h"
#include "calendardir.h"
#define FLAG_LIST_EVENT_ID 1
static const char *charset=RFC2045CHARSET;
void rfc2045_enomem()
{
fprintf(stderr, "Out of memory.\n");
exit(1);
}
PCP_STRERROR
static time_t parse_datetime(int *argn, int argc, char **argv)
{
struct pcp_parse_datetime_info pdi;
memset(&pdi, 0, sizeof(pdi));
pdi.today_name=gettext("today");
pdi.tomorrow_name=gettext("tomorrow");
return (pcp_parse_datetime(argn, argc, argv, &pdi));
}
static const char *from_s()
{
return (gettext("from"));
}
static const char *to_s()
{
return (gettext("to"));
}
static const char *event_s()
{
return (gettext("event"));
}
static const char *on_s()
{
return (gettext("on"));
}
static void error(struct PCP *pcp, int n, const char *s)
{
const char *p;
p=pcp_strerror(n);
if (p)
fprintf(stderr, "%s: %s\n", s, p);
else
fprintf(stderr, "%s: %s\n", s, pcp_errmsg(pcp));
}
struct event_time_list {
struct event_time_list *next;
struct PCP_event_time thetime;
} ;
static int save_time(time_t start, time_t end, void *vp)
{
struct event_time_list **ptr=(struct event_time_list **)vp;
struct event_time_list *etl=
(struct event_time_list *)
malloc(sizeof(struct event_time_list));
if (!etl)
{
perror("malloc");
exit(1);
}
for (; *ptr; ptr=&(*ptr)->next)
;
*ptr=etl;
etl->next=NULL;
etl->thetime.start=start;
etl->thetime.end=end;
return (0);
}
struct participant_list {
struct participant_list *next;
struct PCP_event_participant participant;
} ;
static void usage();
static struct passwd *do_getpw()
{
struct passwd *pw=getpwuid(getuid());
if (!pw)
{
perror("getpwuid");
exit(1);
}
return(pw);
}
struct PCP *open_calendar()
{
struct PCP *pcp;
struct passwd *pw=do_getpw();
char *p;
const char *cp;
FILE *fp;
char authtoken[1024];
p=malloc(strlen(pw->pw_dir)+sizeof("/.pcplogin"));
if (!p)
{
perror("malloc");
exit(1);
}
strcat(strcpy(p, pw->pw_dir), "/.pcplogin");
if ((fp=fopen(p, "r")) != NULL)
{
if (fgets(authtoken, sizeof(authtoken)-2, fp) != NULL)
{
char *q=authtoken+strlen(authtoken);
if (fgets(q, sizeof(authtoken)- (q-authtoken), fp)
!= NULL)
{
char *userid=strtok(authtoken, "\n");
const char *cp;
if (userid)
{
char *password=strtok(NULL, "\n");
char *errmsg;
fclose(fp);
pcp=pcp_reopen_server(userid,
password,
&errmsg);
if (!pcp)
{
printf(gettext("LOGIN ERROR:\n%s\n"),
errmsg ?
errmsg:strerror(errno));
if (errmsg)
free(errmsg);
exit(1);
}
cp=pcp_authtoken(pcp);
if (!cp)
{
fprintf(stderr, gettext("ERROR: Unable to obtain authentication token from the server.\n"));
exit(1);
}
umask(077);
if ((fp=fopen(p, "w")) == NULL)
{
perror(p);
exit(1);
}
fprintf(fp, "%s\n%s\n",
userid,
cp);
if (fflush(fp) || ferror(fp)
|| fclose(fp))
{
perror(p);
unlink(p);
exit(1);
}
free(p);
return (pcp);
}
}
}
fclose(fp);
unlink(p);
}
if ((cp=getenv("PCPDIR")) != NULL && *cp)
{
free(p);
p=strdup(cp);
if (!p)
{
perror("strdup");
exit(1);
}
}
else
{
strcat(strcpy(p, pw->pw_dir), "/.pcp");
}
if (mkdir(p, 0700) == 0)
{
fprintf(stderr, "pcp: created %s\n", p);
}
pcp=pcp_open_dir(p, pw->pw_name);
free(p);
if (!pcp)
{
perror("pcp_open_dir");
exit(1);
}
if (pcp_cleanup(pcp))
{
perror("pcp_cleanup");
pcp_close(pcp);
return (NULL);
}
return (pcp);
}
/**** Add stuff to the calendar ****/
struct add_info {
int (*add_func)(struct add_info *);
const char *add_charset;
char *add_subject;
char *bufptr;
int bufleft;
char buffer[BUFSIZ];
} ;
static int add_info_callback(char *, int, void *);
static int show_conflict(const char *event_id,
time_t from,
time_t to,
const char *addr,
void *dummy)
{
char buf[500];
if (pcp_fmttimerange(buf, sizeof(buf), from, to) < 0)
buf[0]=0;
fprintf(stderr, gettext("Conflict: %s\n (%s)\n"),
buf, event_id);
return (0);
}
static void add(int argn, int argc, char **argv, int flags, const char *old,
struct add_info *add_info)
{
struct event_time_list *list=NULL;
struct participant_list *book=NULL;
const char *subject=NULL;
struct PCP *pcp;
struct PCP_new_eventid *nei;
struct PCP_commit commit_info;
struct PCP_save_event add_event_info;
while (argn < argc)
{
if (strcmp(argv[argn], gettext("with")) == 0)
{
struct participant_list **ptr;
++argn;
if (argn >= argc)
usage();
for (ptr= &book; *ptr; ptr= &(*ptr)->next)
;
if ((*ptr=malloc(sizeof(struct participant_list)))
== NULL)
{
perror("malloc");
exit(1);
}
(*ptr)->participant.address=argv[argn];
(*ptr)->next=NULL;
++argn;
continue;
}
if (strcasecmp(argv[argn], from_s()) == 0)
{
time_t from_time, to_time;
++argn;
if ((from_time=parse_datetime(&argn, argc, argv))
== 0)
usage();
if (argn < argc && strcasecmp(argv[argn], to_s()) == 0)
{
++argn;
if ((to_time=parse_datetime(&argn, argc,
argv)) == 0)
usage();
if (from_time > to_time)
usage();
}
else
{
to_time=from_time + 60 * 60;
}
if (argn < argc && strcmp(argv[argn],
gettext("until")) == 0)
{
++argn;
if (pcp_parse_datetime_until(from_time,
to_time,
&argn,
argc,
argv,
PCP_RECURRING_WEEKLY,
&save_time,
&list))
usage();
}
else
{
save_time(from_time, to_time, &list);
}
continue;
}
if (strcmp(argv[argn], "subject") == 0)
{
if (subject || ++argn >= argc)
usage();
subject=argv[argn++];
continue;
}
usage();
}
memset(&commit_info, 0, sizeof(commit_info));
commit_info.flags=flags;
{
struct event_time_list *p;
struct PCP_event_time *q=0;
for (p=list; p; p=p->next)
++commit_info.n_event_times;
if (!commit_info.n_event_times)
usage();
if ((commit_info.event_times=q=
calloc(commit_info.n_event_times,
sizeof(*commit_info.event_times))) == NULL)
{
perror("malloc");
exit(1);
}
commit_info.n_event_times=0;
for (p=list; p; p=p->next)
q[commit_info.n_event_times++]=p->thetime;
}
memset(&add_event_info, 0, sizeof(add_event_info));
{
struct participant_list *p;
struct PCP_event_participant *q=0;
for (p=book; p; p=p->next)
++add_event_info.n_event_participants;
if (add_event_info.n_event_participants &&
(add_event_info.event_participants=q=
calloc(add_event_info.n_event_participants,
sizeof(*add_event_info.event_participants)))
== NULL)
{
perror("malloc");
exit(1);
return;
}
add_event_info.n_event_participants=0;
for (p=book; p; p=p->next)
q[add_event_info.n_event_participants++]
=p->participant;
}
add_event_info.write_event_func=add_info_callback;
add_event_info.write_event_func_misc_ptr=add_info;
pcp=open_calendar();
nei=pcp_new_eventid(pcp, old, &add_event_info);
if (!nei)
{
pcp_close(pcp);
perror("pcp_new_event_id");
exit(1);
}
commit_info.add_conflict_callback= &show_conflict;
if (pcp_commit(pcp, nei, &commit_info))
{
error(pcp, commit_info.errcode, "pcp_commit");
pcp_destroy_eventid(pcp, nei);
pcp_close(pcp);
exit(1);
}
printf(gettext("Created event %s\n"), nei->eventid);
pcp_destroy_eventid(pcp, nei);
pcp_close(pcp);
exit (0);
}
static int add_info_callback(char *buf, int cnt, void *p)
{
struct add_info *ai=(struct add_info *)p;
int n;
if (!ai->bufleft)
{
n= (*ai->add_func)(ai);
if (n < 0)
return (n);
}
n=0;
while (cnt && ai->bufleft)
{
*buf++ = *ai->bufptr++;
--ai->bufleft;
--cnt;
++n;
}
return (n);
}
static int add_read_stdin(struct add_info *p)
{
int n=read(0, p->buffer, sizeof(p->buffer));
p->bufptr=p->buffer;
if (n < 0)
return (n);
p->bufleft=n;
return (0);
}
static int add_read_stdin_prompt(struct add_info *p)
{
p->add_func=add_read_stdin;
printf(gettext("\nEnter event information, terminate with EOF (usually CTRL-D)\n\n"));
return (add_read_stdin(p));
}
static int add_read_mime(struct add_info *p);
static int add_read_subject(struct add_info *p)
{
strcpy(p->buffer, "Subject: ");
strncat(p->buffer, p->add_subject, sizeof(p->buffer)-100);
strcat(p->buffer, "\n");
p->add_func= &add_read_mime;
p->bufptr=p->buffer;
p->bufleft=strlen(p->buffer);
return (0);
}
static int add_read_mime(struct add_info *p)
{
strcpy(p->buffer, "Mime-Version: 1.0\n"
"Content-Type: text/plain; charset=\"");
strcat(p->buffer, p->add_charset);
strcat(p->buffer, "\"\nContent-Transfer-Encoding: 8bit\n\n");
p->add_func= add_read_stdin_prompt;
p->bufptr=p->buffer;
p->bufleft=strlen(p->buffer);
return (0);
}
/**** List calendar ****/
static int list_callback_saveindex(struct PCP_list_all *, void *);
struct listinfo {
time_t list_from;
time_t list_to;
const char *list_event_id;
int cnt;
struct listinfo_index *index_list;
unsigned i_cnt;
} ;
struct listinfo_index {
struct listinfo_index *next;
size_t from;
size_t to;
char *subject;
char *eventid;
int status;
} ;
static int indexcmp(const void *a, const void *b)
{
struct listinfo_index *ap=*(struct listinfo_index * const *)a;
struct listinfo_index *bp=*(struct listinfo_index * const *)b;
return ( ap->from < bp->from ? -1:
ap->from > bp->from ? 1:
ap->to < bp->to ? -1:
ap->to > bp->to ? 1:0);
}
static void doretr(const char *);
static int save_retr_headers(struct PCP_retr *, const char *,
const char *, void *);
static int save_retr_status(struct PCP_retr *, int, void *);
static void dump_rfc822_hdr(const char *ptr, size_t cnt,
void *dummy)
{
fwrite(ptr, cnt, 1, stdout);
}
static void list(int argn, int argc, char **argv, int flags)
{
struct listinfo listinfo;
int all_flag=0;
int showevent=0;
struct PCP *pcp;
struct PCP_list_all list_all;
memset(&listinfo, 0, sizeof(listinfo));
memset(&list_all, 0, sizeof(list_all));
while (argn < argc)
{
if (strcasecmp(argv[argn], gettext("all")) == 0)
{
all_flag=1;
++argn;
continue;
}
if (strcasecmp(argv[argn], on_s()) == 0)
{
++argn;
if (listinfo.list_from ||
listinfo.list_to ||
(listinfo.list_from=
listinfo.list_to=
parse_datetime(&argn, argc, argv)) == 0)
usage();
showevent=1;
continue;
}
if (strcasecmp(argv[argn], from_s()) == 0)
{
++argn;
if (listinfo.list_from != 0 ||
(listinfo.list_from=
parse_datetime(&argn, argc, argv)) == 0)
usage();
continue;
}
if (strcasecmp(argv[argn], to_s()) == 0)
{
++argn;
if (listinfo.list_to != 0 ||
(listinfo.list_to=
parse_datetime(&argn, argc, argv)) == 0)
usage();
continue;
}
if (strcasecmp(argv[argn], event_s()) == 0)
{
++argn;
if (argn >= argc || listinfo.list_event_id)
usage();
listinfo.list_event_id=argv[argn++];
continue;
}
usage();
}
/* If neither start-end, nor "all" is specified, list events
for today */
if (!all_flag && listinfo.list_from == 0 &&
listinfo.list_to == 0 && !listinfo.list_event_id)
{
time_t t;
struct tm *tmptr;
time(&t);
tmptr=localtime(&t);
pcp_parse_ymd(tmptr->tm_year + 1900,
tmptr->tm_mon + 1,
tmptr->tm_mday,
&listinfo.list_from,
&listinfo.list_to);
}
if ((listinfo.list_from || listinfo.list_to)
&& listinfo.list_event_id)
usage();
if (listinfo.list_event_id)
{
doretr(listinfo.list_event_id);
return;
}
pcp=open_calendar();
list_all.callback_func=list_callback_saveindex;
list_all.callback_arg= &listinfo;
list_all.list_from=listinfo.list_from;
list_all.list_to=listinfo.list_to;
listinfo.i_cnt=0;
if (pcp_list_all(pcp, &list_all))
{
perror("pcp_xlist");
pcp_close(pcp);
exit(1);
}
/* Show event index */
if (listinfo.index_list)
{
unsigned cnt=0, i, maxl;
struct listinfo_index *p, **ary;
const char **event_id_list;
struct PCP_retr r;
for (p=listinfo.index_list; p; p=p->next)
++cnt;
event_id_list=(const char **)
malloc(sizeof(const char *)*(cnt+1));
if (!event_id_list)
{
perror("malloc");
exit(1);
}
cnt=0;
for (p=listinfo.index_list; p; p=p->next)
event_id_list[cnt++]=p->eventid;
event_id_list[cnt]=0;
memset(&r, 0, sizeof(r));
r.callback_arg=&listinfo;
r.callback_retr_status=save_retr_status;
r.callback_arg=&listinfo;
r.event_id_list=event_id_list;
if (pcp_retr(pcp, &r))
{
error(pcp, r.errcode, "pcp_retr");
pcp_close(pcp);
exit(1);
}
r.callback_headers_func=save_retr_headers;
if (pcp_retr(pcp, &r))
{
error(pcp, r.errcode, "pcp_retr");
pcp_close(pcp);
exit(1);
}
free(event_id_list);
ary=(struct listinfo_index **)
malloc(sizeof(struct listinfo_index *)
* listinfo.i_cnt);
if (!ary)
{
perror("malloc");
pcp_close(pcp);
exit(1);
}
cnt=0;
for (p=listinfo.index_list; p; p=p->next)
ary[cnt++]=p;
qsort(ary, cnt, sizeof(ary[0]), indexcmp);
maxl=20;
for (i=0; i<cnt; i++)
{
char fromto[500];
if (pcp_fmttimerange(fromto, sizeof(fromto),
ary[i]->from,
ary[i]->to) == 0 &&
strlen(fromto) > maxl)
maxl=strlen(fromto);
}
for (i=0; i<cnt; i++)
{
char fromto[500];
if (pcp_fmttimerange(fromto, sizeof(fromto),
ary[i]->from,
ary[i]->to) < 0)
strcpy(fromto, "******");
printf("%-*s %s%s", (int)maxl, fromto,
ary[i]->status & LIST_CANCELLED
? gettext("CANCELLED: "):"",
ary[i]->status & LIST_BOOKED
? gettext("(event not yet commited) "):"");
if (rfc822_display_hdrvalue("subject",
ary[i]->subject
? ary[i]->subject:"",
charset,
dump_rfc822_hdr,
NULL, NULL) < 0)
{
printf("%s",
ary[i]->subject
? ary[i]->subject:"");
}
printf("\n");
if (flags & FLAG_LIST_EVENT_ID)
printf("%-*s(%s)\n", (int)maxl, "",
ary[i]->eventid);
}
free(ary);
listinfo.cnt=cnt;
}
printf(gettext("%d events found.\n"), listinfo.cnt);
while (listinfo.index_list)
{
struct listinfo_index *p=listinfo.index_list;
listinfo.index_list=p->next;
free(p->eventid);
if (p->subject)
free(p->subject);
free(p);
}
pcp_close(pcp);
}
static int list_callback_saveindex(struct PCP_list_all *xl, void *vp)
{
struct listinfo *li=(struct listinfo *)vp;
struct listinfo_index *i;
li->cnt++;
if ((i=(struct listinfo_index *)
malloc(sizeof(struct listinfo_index))) == NULL)
{
perror("malloc");
exit(1);
}
memset(i, 0, sizeof(*i));
if ((i->eventid=strdup(xl->event_id)) == NULL)
{
free(i);
perror("malloc");
exit(1);
}
i->next=li->index_list;
li->index_list=i;
++li->i_cnt;
i->from=xl->event_from;
i->to=xl->event_to;
i->subject=NULL;
return (0);
}
static int save_retr_status(struct PCP_retr *r, int status, void *vp)
{
struct listinfo *l=(struct listinfo *)vp;
struct listinfo_index *i;
for (i=l->index_list; i; i=i->next)
if (strcmp(i->eventid, r->event_id) == 0)
{
i->status=status;
}
return (0);
}
static int save_retr_headers(struct PCP_retr *ri, const char *h,
const char *v, void *vp)
{
struct listinfo *l=(struct listinfo *)vp;
struct listinfo_index *i;
char *p, *q;
if (strcasecmp(h, "subject"))
return (0);
for (i=l->index_list; i; i=i->next)
if (strcmp(i->eventid, ri->event_id) == 0)
{
if (!i->subject)
{
i->subject=strdup(v);
if (!i->subject)
return (-1);
}
for (p=q=i->subject; *p; )
{
if (*p == '\n')
{
while (*p && isspace((int)
(unsigned char)
*p))
++p;
*q++=' ';
continue;
}
*q++ = *p++;
}
*q=0;
}
return (0);
}
static int doretr_begin(struct PCP_retr *r, void *vp);
static int doretr_save(struct PCP_retr *, const char *, int, void *);
static int do_show_retr(struct PCP_retr *, void *);
struct xretrinfo {
FILE *tmpfile;
int status;
struct xretr_participant_list *participant_list;
struct xretr_time_list *time_list;
} ;
struct xretr_participant_list {
struct xretr_participant_list *next;
char *participant;
} ;
struct xretr_time_list {
struct xretr_time_list *next;
time_t from;
time_t to;
} ;
static int doretr_status(struct PCP_retr *p, int status, void *vp)
{
struct xretrinfo *xr=(struct xretrinfo *)vp;
xr->status=status;
return (0);
}
static int doretr_date(struct PCP_retr *p, time_t from, time_t to, void *vp)
{
struct xretrinfo *xr=(struct xretrinfo *)vp;
struct xretr_time_list *t=malloc(sizeof(struct xretr_time_list));
if (!t)
return (-1);
t->next=xr->time_list;
xr->time_list=t;
t->from=from;
t->to=to;
return (0);
}
static int doretr_participants(struct PCP_retr *p, const char *n,
const char *id, void *vp)
{
struct xretrinfo *xr=(struct xretrinfo *)vp;
char *s=strdup(n);
struct xretr_participant_list *pa;
if (!s)
return (-1);
if ((pa=malloc(sizeof(struct xretr_participant_list))) == NULL)
{
free(s);
return (-1);
}
pa->participant=s;
pa->next=xr->participant_list;
xr->participant_list=pa;
return (0);
}
static void doretr(const char *eventid)
{
struct PCP *pcp;
struct PCP_retr r;
struct xretrinfo xr;
const char *event_id_array[2];
struct xretr_time_list *tl;
struct xretr_participant_list *pl;
pcp=open_calendar();
memset(&r, 0, sizeof(r));
memset(&xr, 0, sizeof(xr));
r.callback_arg= &xr;
r.callback_retr_status=doretr_status;
r.callback_retr_date=doretr_date;
r.callback_retr_participants=doretr_participants;
event_id_array[0]=eventid;
event_id_array[1]=NULL;
r.event_id_list=event_id_array;
if (pcp_retr(pcp, &r) == 0)
{
r.callback_retr_status=NULL;
r.callback_retr_date=NULL;
r.callback_retr_participants=NULL;
r.callback_begin_func=doretr_begin;
r.callback_rfc822_func=doretr_save;
r.callback_end_func=do_show_retr;
if (pcp_retr(pcp, &r) == 0)
{
pcp_close(pcp);
}
else
{
error(pcp, r.errcode, "pcp_retr");
pcp_close(pcp);
}
}
else
{
error(pcp, r.errcode, "pcp_retr");
pcp_close(pcp);
}
while ((pl=xr.participant_list) != NULL)
{
xr.participant_list=pl->next;
free(pl->participant);
free(pl);
}
while ((tl=xr.time_list) != NULL)
{
xr.time_list=tl->next;
free(tl);
}
}
static int doretr_begin(struct PCP_retr *r, void *vp)
{
struct xretrinfo *xr=(struct xretrinfo *)vp;
if ((xr->tmpfile=tmpfile()) == NULL)
return (-1);
return (0);
}
static int doretr_save(struct PCP_retr *r, const char *p, int n, void *vp)
{
struct xretrinfo *xr=(struct xretrinfo *)vp;
if (fwrite(p, n, 1, xr->tmpfile) != 1)
return (-1);
return (0);
}
static int tcmp(const void *a, const void *b)
{
struct xretr_time_list *ap=*(struct xretr_time_list **)a;
struct xretr_time_list *bp=*(struct xretr_time_list **)b;
return ( ap->from < bp->from ? -1:
ap->from > bp->from ? 1:
ap->to < bp->to ? -1:
ap->to > bp->to ? 1:0);
}
static int list_msg_rfc822(struct rfc2045 *, FILE *);
static int do_show_retr(struct PCP_retr *r, void *vp)
{
struct xretrinfo *xr=(struct xretrinfo *)vp;
struct xretr_participant_list *p;
struct xretr_time_list *t, **tt;
unsigned cnt, i;
struct rfc2045 *rfcp;
int rc;
if (fseek(xr->tmpfile, 0L, SEEK_SET) < 0
|| lseek(fileno(xr->tmpfile), 0L, SEEK_SET) < 0)
{
fclose(xr->tmpfile);
return (-1);
}
if (xr->time_list == NULL)
{
fclose(xr->tmpfile);
return (0);
}
printf(gettext("Event: %s\n"), r->event_id);
for (cnt=0, t=xr->time_list; t; t=t->next)
++cnt;
tt=(struct xretr_time_list **)malloc(cnt * sizeof(*t));
if (!tt)
{
fclose(xr->tmpfile);
return (-1);
}
for (cnt=0, t=xr->time_list; t; t=t->next)
tt[cnt++]=t;
qsort(tt, cnt, sizeof(*tt), tcmp);
for (i=0; i<cnt; i++)
{
char fromto[500];
if (pcp_fmttimerange(fromto, sizeof(fromto),
tt[i]->from, tt[i]->to) < 0)
strcpy(fromto, "******");
printf(gettext(" %s\n"), fromto);
}
free(tt);
if (xr->status & LIST_CANCELLED)
printf(gettext(" **** CANCELLED ****\n"));
if (xr->status & LIST_BOOKED)
printf(gettext(" **** EVENT NOT YET COMMITED ****\n"));
for (p=xr->participant_list; p; p=p->next)
printf(gettext(" Participant: %s\n"), p->participant);
rfcp=rfc2045_fromfp(xr->tmpfile);
if (!rfcp)
{
fclose(xr->tmpfile);
return (-1);
}
rc=list_msg_rfc822(rfcp, xr->tmpfile);
rfc2045_free(rfcp);
fclose(xr->tmpfile);
return (rc);
}
static int list_msg_mime(struct rfc2045 *, FILE *);
static int list_msg_rfc822(struct rfc2045 *rfc, FILE *fp)
{
off_t start_pos, end_pos, start_body;
off_t dummy, pos;
struct rfc822hdr h;
rfc2045_mimepos(rfc, &start_pos, &end_pos, &start_body,
&dummy, &dummy);
if (fseek(fp, start_pos, SEEK_SET) < 0)
return (-1);
pos=start_pos;
rfc822hdr_init(&h, 8192);
while (rfc822hdr_read(&h, fp, &pos, start_body) == 0)
{
printf("%s: ", h.header);
if (rfc822_display_hdrvalue(h.header, h.value, charset,
dump_rfc822_hdr, NULL, NULL) < 0)
{
printf("%s", h.value);
}
printf("\n");
}
rfc822hdr_free(&h);
printf("\n");
return (list_msg_mime(rfc, fp));
}
static int list_msg_rfc822_part(struct rfc2045 *rfc, FILE *fp)
{
struct rfc2045 *q;
for (q=rfc->firstpart; q; q=q->next)
{
if (q->isdummy) continue;
return (list_msg_rfc822(q, fp));
}
return (0);
}
static int list_msg_mime_multipart(struct rfc2045 *, FILE *);
static int list_msg_mime_multipart_alternative(struct rfc2045 *, FILE *);
static int list_msg_textplain(struct rfc2045 *, FILE *);
static int (*mime_handler(struct rfc2045 *rfc))(struct rfc2045 *, FILE *)
{
const char *content_type, *dummy;
rfc2045_mimeinfo(rfc, &content_type, &dummy, &dummy);
if (strcmp(content_type, "multipart/alternative") == 0)
return ( &list_msg_mime_multipart_alternative);
if (strncmp(content_type, "multipart/", 10) == 0)
return ( &list_msg_mime_multipart);
if (strcmp(content_type, "message/rfc822") == 0)
return ( &list_msg_rfc822_part );
if (strcmp(content_type, "text/plain") == 0
|| strcmp(content_type, "text/rfc822-headers") == 0
|| strcmp(content_type, "message/delivery-status") == 0)
return ( &list_msg_textplain);
return (NULL);
}
static int list_msg_mime(struct rfc2045 *rfc, FILE *fp)
{
int (*handler)(struct rfc2045 *, FILE *)=
mime_handler(rfc);
const char *content_type, *dummy;
char *disposition_name;
char *disposition_filename;
char *content_name;
const char *disposition_filename_s;
off_t start_pos, end_pos, start_body;
off_t dummy2;
char buffer[NUMBUFSIZE+10];
if (handler)
return ( (*handler)(rfc, fp));
rfc2045_mimeinfo(rfc, &content_type, &dummy, &dummy);
if (rfc2231_udecodeDisposition(rfc, "name", NULL, &disposition_name)<0
||
rfc2231_udecodeDisposition(rfc, "filename", NULL,
&disposition_filename) < 0
||
rfc2231_udecodeType(rfc, "name", NULL,
&content_name) < 0)
{
perror("malloc");
exit(1);
}
rfc2045_mimepos(rfc, &start_pos, &end_pos, &start_body,
&dummy2, &dummy2);
disposition_filename_s=disposition_filename;
if (!*disposition_filename_s)
disposition_filename_s=content_name;
if (!disposition_filename_s || !*disposition_filename_s)
disposition_filename_s=disposition_name;
printf(gettext("Attachment: %s (%s)\n"), content_type,
libmail_str_sizekb(end_pos - start_body, buffer));
if (disposition_filename_s && *disposition_filename_s)
printf(" %s\n", disposition_filename_s);
printf("\n");
free(content_name);
free(disposition_name);
free(disposition_filename);
return (0);
}
static int list_msg_mime_multipart(struct rfc2045 *rfc, FILE *fp)
{
struct rfc2045 *q;
int first=1;
int rc;
for (q=rfc->firstpart; q; q=q->next)
{
if (q->isdummy) continue;
if (!first)
printf("\n ------------------------------\n\n");
first=0;
rc=list_msg_mime(q, fp);
if (rc)
return (rc);
}
return (0);
}
static int list_msg_mime_multipart_alternative(struct rfc2045 *rfc, FILE *fp)
{
struct rfc2045 *q, *first=NULL, *last=NULL;
for (q=rfc->firstpart; q; q=q->next)
{
if (q->isdummy) continue;
if (!first)
first=q;
if ( mime_handler(q) != NULL)
last=q;
}
return (last ? list_msg_mime(last, fp):
first ? list_msg_mime(first, fp):0);
}
static int textplain_output(const char *ptr, size_t cnt, void *voidptr)
{
while (cnt)
{
putchar(*ptr);
++ptr;
--cnt;
}
return (0);
}
static int list_msg_textplain(struct rfc2045 *rfc, FILE *fp)
{
const char *mime_charset, *dummy;
int rc;
struct rfc2045src *src;
rfc2045_mimeinfo(rfc, &dummy, &dummy, &mime_charset);
if (strcasecmp(mime_charset, charset))
{
printf(gettext(" (The following text was converted from %s)\n\n"),
mime_charset);
}
src=rfc2045src_init_fd(fileno(fp));
if (src == NULL)
return (-1);
rc=rfc2045_decodetextmimesection(src,
rfc,
charset,
NULL,
textplain_output, NULL);
printf("\n");
rfc2045src_deinit(src);
return (rc);
}
/*** CANCEL/UNCANCEL/DELETE ***/
static void docancel(const char *id, int flags)
{
struct PCP *pcp=open_calendar();
int errcode;
if (pcp_cancel(pcp, id, &errcode))
{
error(pcp, errcode, "pcp_cancel");
exit(1);
}
pcp_close(pcp);
}
static void dodelete(const char *id, int flags)
{
struct PCP *pcp=open_calendar();
struct PCP_delete del;
memset(&del, 0, sizeof(del));
del.id=id;
if (pcp_delete(pcp, &del))
{
error(pcp, del.errcode, "pcp_delete");
exit(1);
}
pcp_close(pcp);
}
static void douncancel(const char *id, int flags)
{
struct PCP *pcp=open_calendar();
struct PCP_uncancel uncancel_info;
memset(&uncancel_info, 0, sizeof(uncancel_info));
uncancel_info.uncancel_conflict_callback= &show_conflict;
uncancel_info.uncancel_conflict_callback_ptr=NULL;
if (pcp_uncancel(pcp, id, flags, &uncancel_info))
{
error(pcp, uncancel_info.errcode, "pcp_uncancel");
exit(1);
}
pcp_close(pcp);
}
/* Initialize */
static void init(const char *shell)
{
struct passwd *pw=do_getpw();
if (chdir(pw->pw_dir))
{
perror(pw->pw_dir);
exit(1);
}
unlink(".pcplogin");
}
/* Login to a server */
static void login(const char *userid)
{
char *errmsg;
char password[1024];
struct PCP *pcp;
char *p;
#if HAVE_TCGETATTR
struct termios tios;
int tios_rc=tcgetattr(0, &tios);
if (tios_rc >= 0)
{
tios.c_lflag &= ~ECHO;
tcsetattr(0, TCSANOW, &tios);
}
#endif
printf(gettext("Password: "));
if (fgets(password, sizeof(password), stdin) == NULL)
password[0]=0;
#if HAVE_TCGETATTR
if (tios_rc >= 0)
{
tios.c_lflag |= ECHO;
tcsetattr(0, TCSANOW, &tios);
printf("\n");
}
#endif
if ((p=strchr(password, '\n')) != 0)
*p=0;
pcp=pcp_open_server(userid, password, &errmsg);
if (pcp)
{
struct passwd *pw=do_getpw();
FILE *fp;
const char *p=pcp_authtoken(pcp);
if (!p)
{
fprintf(stderr, gettext("ERROR: Unable to obtain authentication token from the server.\n"));
exit(1);
}
if (chdir(pw->pw_dir) < 0)
{
perror(pw->pw_dir);
exit(1);
}
umask(077);
fp=fopen(".pcplogin", "w");
if (!fp)
{
perror("$HOME/.pcplogin");
exit(1);
}
fprintf(fp, "%s\n%s\n", userid, p);
if (fflush(fp) < 0 || ferror(fp) || fclose(fp))
{
perror("$HOME/.pcplogin");
unlink(".pcplogin");
exit(1);
}
pcp_close(pcp);
return;
}
printf(gettext("ERROR:\n%s\n"), errmsg ? errmsg:strerror(errno));
if (errmsg)
free(errmsg);
}
/* setacl */
static void setacl(const char *who, int flags)
{
struct PCP *pcp=open_calendar();
if (pcp_has_acl(pcp))
{
if (pcp_acl(pcp, who, flags))
{
error(pcp, 0, "pcp_acl");
exit(1);
}
}
else
{
fprintf(stderr, gettext("ERROR: ACLs not supported.\n"));
}
pcp_close(pcp);
}
static int do_list_acl(const char *who, int flags, void *dummy)
{
char buf[1024];
buf[0]=0;
pcp_acl_name(flags, buf);
printf("%-30s\t%s\n", who, buf);
return (0);
}
static void listacls()
{
struct PCP *pcp=open_calendar();
if (pcp_has_acl(pcp))
{
if (pcp_list_acl(pcp, do_list_acl, NULL))
{
error(pcp, 0, "pcp_list_acl");
exit(1);
}
}
else
{
fprintf(stderr, gettext("ERROR: ACLs not supported.\n"));
}
pcp_close(pcp);
}
/* Connect to a PCP server */
static int doconnect(const char *pathname)
{
int fd=socket(PF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un skun;
skun.sun_family=AF_UNIX;
strcpy(skun.sun_path, pathname);
if (fd >= 0 && fcntl(fd, F_SETFL, O_NONBLOCK) >= 0)
{
if (connect(fd, (struct sockaddr *)&skun, sizeof(skun)) == 0)
return (fd);
if (errno == EINPROGRESS || errno == EWOULDBLOCK)
{
struct timeval tv;
fd_set fds;
int rc;
tv.tv_sec=10;
tv.tv_usec=0;
FD_ZERO(&fds);
FD_SET(fd, &fds);
rc=select(fd+1, NULL, &fds, NULL, &tv);
if (rc > 1 && FD_ISSET(fd, &fds))
{
if (connect(fd, (struct sockaddr *)&skun,
sizeof(skun)) == 0)
return (fd);
if (errno == EISCONN)
return (fd);
}
if (rc >= 0)
errno=ETIMEDOUT;
}
}
perror(pathname);
exit(1);
return (0);
}
static void doconnectwrite(int, const char *, int);
static void doconnectloop(int fd)
{
char buf[BUFSIZ];
fd_set rfd;
for (;;)
{
FD_ZERO(&rfd);
FD_SET(0, &rfd);
FD_SET(fd, &rfd);
if (select(fd+1, &rfd, NULL, NULL, NULL) <= 0)
{
perror("select");
continue;
}
if (FD_ISSET(fd, &rfd))
{
int n=read(fd, buf, sizeof(buf));
if (n < 0)
perror("read");
if (n <= 0)
break;
doconnectwrite(1, buf, n);
}
if (FD_ISSET(0, &rfd))
{
int n=read(0, buf, sizeof(buf));
if (n < 0)
perror("read");
if (n <= 0)
break;
doconnectwrite(fd, buf, n);
}
}
exit(0);
}
static void doconnectwrite(int fd, const char *p, int cnt)
{
while (cnt > 0)
{
int n=write(fd, p, cnt);
if (n <= 0)
exit(0);
p += n;
cnt -= n;
}
}
static void usage()
{
const char *charset=unicode_default_chset();
fprintf(stderr,
gettext("Usage: pcp [options] [command]\n"
"\n"
"Options:\n"
" -c - add/uncancel event that conflicts with an existing event\n"
" -s subject - specify event subject\n"
" -C charset - specify your local charset (default %s)\n"
" -m - standard input is already a MIME-formatted message\n"
" -e - list event ids\n"
"\n"), charset);
fprintf(stderr, "%s",
gettext(
"Commands:\n"
" init\n"
" login USERID\n"
" logout\n"
" add from FROM to TO [ from FROM to TO...]\n"
" update ID from FROM to TO [ from FROM to TO...]\n"
" list [all] [from FROM] [to TO] [event ID]\n"
" cancel ID\n"
" uncancel ID\n"
" delete ID\n"
" connect [/pathname]\n"
" sconnect [/pathname]\n"
" setacl [MODIFY|CONFLICT|LIST|RETR|NONE]*\n"
" listacl\n"
));
exit(1);
}
static char *read_subject()
{
char buf[BUFSIZ];
char *p;
printf("Subject: ");
if (fgets(buf, sizeof(buf), stdin) == NULL)
exit(0);
p=strchr(buf, '\n');
if (p)
*p=0;
p=strdup(buf);
if (!p)
{
perror("malloc");
exit(1);
}
return (p);
}
static char *mimeify(const char *subject, const char *charset)
{
char *p=rfc2047_encode_str(subject, charset,
rfc2047_qp_allow_any);
if (!p)
{
perror("rfc2047_encode_str");
exit(1);
}
return (p);
}
int main(int argc, char **argv)
{
int flags=0;
int list_flags=0;
int optchar;
const char *subject=0;
int ismime=0;
setlocale(LC_ALL, "");
textdomain("pcp");
charset=unicode_default_chset();
while ((optchar=getopt(argc, argv, "emcs:C:")) >= 0)
{
switch (optchar) {
case 'c':
flags |= PCP_OK_CONFLICT;
break;
case 's':
subject=optarg;
break;
case 'C':
charset=optarg;
break;
case 'm':
ismime=1;
break;
case 'e':
list_flags |= FLAG_LIST_EVENT_ID;
break;
default:
usage();
}
}
if (optind < argc)
{
const char *addstr=gettext("add");
const char *updatestr=gettext("update");
if (strcmp(argv[optind], gettext("init")) == 0)
{
++optind;
init(optind < argc ? argv[optind]:NULL);
exit(0);
}
else if (strcmp(argv[optind], gettext("login")) == 0)
{
++optind;
if (optind < argc)
{
login(argv[optind]);
exit (0);
}
}
else if (strcmp(argv[optind], gettext("connect")) == 0)
{
int fd;
const char *n;
++optind;
n=optind < argc ? argv[optind] : PUBDIR "/50PCPDLOCAL";
fd=doconnect(n);
if (fcntl(fd, F_SETFL, 0) < 0)
{
perror(argv[optind]);
exit (0);
}
printf("Connected to %s...\n", n);
doconnectloop(fd);
exit (0);
}
else if (strcmp(argv[optind], gettext("sconnect")) == 0)
{
int fd;
const char *n;
++optind;
n=optind < argc ? argv[optind]
: PRIVDIR "/50PCPDLOCAL";
fd=doconnect(n);
if (fcntl(fd, F_SETFL, 0) < 0)
{
perror(argv[optind]);
exit (0);
}
printf("Connected to %s...\n", n);
doconnectloop(fd);
exit (0);
}
else if (strcmp(argv[optind], gettext("cancel")) == 0)
{
++optind;
if (optind < argc)
{
docancel(argv[optind], flags);
exit (0);
}
}
else if (strcmp(argv[optind], gettext("delete")) == 0)
{
++optind;
if (optind < argc)
{
dodelete(argv[optind], flags);
exit (0);
}
}
else if (strcmp(argv[optind], gettext("uncancel")) == 0)
{
++optind;
if (optind < argc)
{
douncancel(argv[optind], flags);
exit (0);
}
}
else if (strcmp(argv[optind], addstr) == 0 ||
strcmp(argv[optind], updatestr) == 0)
{
struct add_info info;
const char *oldeventid=0;
++optind;
if (strcmp(argv[optind-1], updatestr) == 0)
{
if (optind >= argc)
usage();
oldeventid=argv[optind++];
}
memset(&info, 0, sizeof(info));
if (ismime)
info.add_func=add_read_stdin;
else
{
info.add_func=add_read_subject;
info.add_charset=charset;
if (subject)
info.add_subject=mimeify(subject,
charset);
else
{
char *p;
if (!isatty(0))
{
fprintf(stderr,
gettext("Error: -s is required\n"));
exit(1);
}
p=read_subject();
info.add_subject=mimeify(p, charset);
free(p);
}
}
add(optind, argc, argv, flags, oldeventid, &info);
exit (0);
}
else if (strcmp(argv[optind], gettext("list")) == 0)
{
list(optind+1, argc, argv, list_flags);
exit (0);
}
else if (strcmp(argv[optind], gettext("setacl")) == 0)
{
int flags=0;
const char *acl;
if (++optind < argc)
{
acl=argv[optind];
while (++optind < argc)
flags |= pcp_acl_num(argv[optind]);
setacl(acl, flags);
}
exit (0);
}
else if (strcmp(argv[optind], gettext("listacl")) == 0)
{
listacls();
exit(0);
}
}
usage();
return (0);
}