Back to index

courier  0.68.2
pcp.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2001-2011 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 
00007 #include "config.h"
00008 #include <stdio.h>
00009 #include <stdlib.h>
00010 #include <string.h>
00011 #include <ctype.h>
00012 #include <errno.h>
00013 #include <signal.h>
00014 #include <unistd.h>
00015 #include <langinfo.h>
00016 #if HAVE_TERMIOS_H
00017 #include <termios.h>
00018 #endif
00019 #include <fcntl.h>
00020 #include <locale.h>
00021 #include <libintl.h>
00022 #include <sys/types.h>
00023 #include <sys/stat.h>
00024 #include <sys/socket.h>
00025 #include <sys/un.h>
00026 #include <pwd.h>
00027 #include <rfc822/rfc822.h>
00028 #include <rfc822/rfc2047.h>
00029 #include <rfc822/rfc822hdr.h>
00030 #include <rfc2045/rfc2045.h>
00031 #include <rfc2045/rfc2045charset.h>
00032 #include <unicode/unicode.h>
00033 #include <numlib/numlib.h>
00034 
00035 #define PCP_ERRMSG(s) gettext(s)
00036 
00037 #include "pcp.h"
00038 #include "calendardir.h"
00039 
00040 #define FLAG_LIST_EVENT_ID  1
00041 
00042 static const char *charset=RFC2045CHARSET;
00043 
00044 void rfc2045_enomem()
00045 {
00046        fprintf(stderr, "Out of memory.\n");
00047        exit(1);
00048 }
00049 
00050 PCP_STRERROR
00051 
00052 static time_t parse_datetime(int *argn, int argc, char **argv)
00053 {
00054        struct pcp_parse_datetime_info pdi;
00055 
00056        memset(&pdi, 0, sizeof(pdi));
00057 
00058        pdi.today_name=gettext("today");
00059        pdi.tomorrow_name=gettext("tomorrow");
00060 
00061        return (pcp_parse_datetime(argn, argc, argv, &pdi));
00062 }
00063 
00064 static const char *from_s()
00065 {
00066        return (gettext("from"));
00067 }
00068 
00069 static const char *to_s()
00070 {
00071        return (gettext("to"));
00072 }
00073 
00074 static const char *event_s()
00075 {
00076        return (gettext("event"));
00077 }
00078 
00079 static const char *on_s()
00080 {
00081        return (gettext("on"));
00082 }
00083 
00084 static void error(struct PCP *pcp, int n, const char *s)
00085 {
00086        const char *p;
00087 
00088        p=pcp_strerror(n);
00089 
00090        if (p)
00091               fprintf(stderr, "%s: %s\n", s, p);
00092        else
00093               fprintf(stderr, "%s: %s\n", s, pcp_errmsg(pcp));
00094 }
00095 
00096 struct event_time_list {
00097        struct event_time_list *next;
00098        struct PCP_event_time thetime;
00099 } ;
00100 
00101 static int save_time(time_t start, time_t end, void *vp)
00102 {
00103        struct event_time_list **ptr=(struct event_time_list **)vp;
00104        struct event_time_list *etl=
00105               (struct event_time_list *)
00106               malloc(sizeof(struct event_time_list));
00107 
00108        if (!etl)
00109        {
00110               perror("malloc");
00111               exit(1);
00112        }
00113 
00114        for (; *ptr; ptr=&(*ptr)->next)
00115                             ;
00116        *ptr=etl;
00117        etl->next=NULL;
00118 
00119        etl->thetime.start=start;
00120        etl->thetime.end=end;
00121        return (0);
00122 }
00123 
00124 
00125 struct participant_list {
00126        struct participant_list *next;
00127        struct PCP_event_participant participant;
00128 } ;
00129 
00130 static void usage();
00131 
00132 static struct passwd *do_getpw()
00133 {
00134        struct passwd *pw=getpwuid(getuid());
00135 
00136        if (!pw)
00137        {
00138               perror("getpwuid");
00139               exit(1);
00140        }
00141        return(pw);
00142 }
00143 
00144 struct PCP *open_calendar()
00145 {
00146        struct PCP *pcp;
00147        struct passwd *pw=do_getpw();
00148        char *p;
00149        const char *cp;
00150        FILE *fp;
00151        char authtoken[1024];
00152 
00153        p=malloc(strlen(pw->pw_dir)+sizeof("/.pcplogin"));
00154        if (!p)
00155        {
00156               perror("malloc");
00157               exit(1);
00158        }
00159 
00160        strcat(strcpy(p, pw->pw_dir), "/.pcplogin");
00161 
00162        if ((fp=fopen(p, "r")) != NULL)
00163        {
00164               if (fgets(authtoken, sizeof(authtoken)-2, fp) != NULL)
00165               {
00166                      char *q=authtoken+strlen(authtoken);
00167 
00168                      if (fgets(q, sizeof(authtoken)- (q-authtoken), fp)
00169                          != NULL)
00170                      {
00171                             char *userid=strtok(authtoken, "\n");
00172                             const char *cp;
00173 
00174                             if (userid)
00175                             {
00176                                    char *password=strtok(NULL, "\n");
00177                                    char *errmsg;
00178 
00179                                    fclose(fp);
00180 
00181                                    pcp=pcp_reopen_server(userid,
00182                                                        password,
00183                                                        &errmsg);
00184 
00185                                    if (!pcp)
00186                                    {
00187                                           printf(gettext("LOGIN ERROR:\n%s\n"),
00188                                                  errmsg ?
00189                                                  errmsg:strerror(errno));
00190                                           if (errmsg)
00191                                                  free(errmsg);
00192                                           exit(1);
00193                                    }
00194 
00195                                    cp=pcp_authtoken(pcp);
00196 
00197                                    if (!cp)
00198                                    {
00199                                           fprintf(stderr, gettext("ERROR: Unable to obtain authentication token from the server.\n"));
00200                                           exit(1);
00201                                    }
00202 
00203                                    umask(077);
00204 
00205                                    if ((fp=fopen(p, "w")) == NULL)
00206                                    {
00207                                           perror(p);
00208                                           exit(1);
00209                                    }
00210 
00211                                    fprintf(fp, "%s\n%s\n",
00212                                           userid,
00213                                           cp);
00214                                    if (fflush(fp) || ferror(fp)
00215                                        || fclose(fp))
00216                                    {
00217                                           perror(p);
00218                                           unlink(p);
00219                                           exit(1);
00220                                    }
00221                                    free(p);
00222                                    return (pcp);
00223                             }
00224                      }
00225               }
00226               fclose(fp);
00227               unlink(p);
00228        }
00229 
00230        if ((cp=getenv("PCPDIR")) != NULL && *cp)
00231        {
00232               free(p);
00233               p=strdup(cp);
00234               if (!p)
00235               {
00236                      perror("strdup");
00237                      exit(1);
00238               }
00239        }
00240        else
00241        {
00242               strcat(strcpy(p, pw->pw_dir), "/.pcp");
00243        }
00244 
00245        if (mkdir(p, 0700) == 0)
00246        {
00247               fprintf(stderr, "pcp: created %s\n", p);
00248        }
00249 
00250        pcp=pcp_open_dir(p, pw->pw_name);
00251        free(p);
00252 
00253        if (!pcp)
00254        {
00255               perror("pcp_open_dir");
00256               exit(1);
00257        }
00258 
00259        if (pcp_cleanup(pcp))
00260        {
00261               perror("pcp_cleanup");
00262               pcp_close(pcp);
00263               return (NULL);
00264        }
00265        return (pcp);
00266 }
00267 
00268 /**** Add stuff to the calendar ****/
00269 
00270 struct add_info {
00271        int (*add_func)(struct add_info *);
00272        const char *add_charset;
00273        char *add_subject;
00274 
00275        char *bufptr;
00276        int bufleft;
00277        char buffer[BUFSIZ];
00278 
00279 } ;
00280 
00281 static int add_info_callback(char *, int, void *);
00282 
00283 static int show_conflict(const char *event_id,
00284                       time_t from,
00285                       time_t to,
00286                       const char *addr,
00287                       void *dummy)
00288 {
00289        char buf[500];
00290 
00291        if (pcp_fmttimerange(buf, sizeof(buf), from, to) < 0)
00292               buf[0]=0;
00293 
00294        fprintf(stderr, gettext("Conflict: %s\n    (%s)\n"),
00295               buf, event_id);
00296        return (0);
00297 }
00298 
00299 static void add(int argn, int argc, char **argv, int flags, const char *old,
00300               struct add_info *add_info)
00301 {
00302        struct event_time_list *list=NULL;
00303        struct participant_list *book=NULL;
00304 
00305        const char *subject=NULL;
00306        struct PCP *pcp;
00307        struct PCP_new_eventid *nei;
00308        struct PCP_commit commit_info;
00309        struct PCP_save_event add_event_info;
00310 
00311        while (argn < argc)
00312        {
00313               if (strcmp(argv[argn], gettext("with")) == 0)
00314               {
00315                      struct participant_list **ptr;
00316 
00317                      ++argn;
00318                      if (argn >= argc)
00319                             usage();
00320 
00321                      for (ptr= &book; *ptr; ptr= &(*ptr)->next)
00322                             ;
00323 
00324                      if ((*ptr=malloc(sizeof(struct participant_list)))
00325                          == NULL)
00326                      {
00327                             perror("malloc");
00328                             exit(1);
00329                      }
00330                      (*ptr)->participant.address=argv[argn];
00331                      (*ptr)->next=NULL;
00332                      ++argn;
00333                      continue;
00334               }
00335 
00336               if (strcasecmp(argv[argn], from_s()) == 0)
00337               {
00338                      time_t from_time, to_time;
00339 
00340                      ++argn;
00341                      if ((from_time=parse_datetime(&argn, argc, argv))
00342                          == 0)
00343                             usage();
00344 
00345                      if (argn < argc && strcasecmp(argv[argn], to_s()) == 0)
00346                      {
00347                             ++argn;
00348                             if ((to_time=parse_datetime(&argn, argc,
00349                                                      argv)) == 0)
00350                                    usage();
00351 
00352                             if (from_time > to_time)
00353                                    usage();
00354                      }
00355                      else
00356                      {
00357                             to_time=from_time + 60 * 60;
00358                      }
00359 
00360                      if (argn < argc && strcmp(argv[argn],
00361                                             gettext("until")) == 0)
00362                      {
00363                             ++argn;
00364 
00365                             if (pcp_parse_datetime_until(from_time,
00366                                                       to_time,
00367                                                       &argn,
00368                                                       argc,
00369                                                       argv,
00370 
00371                                                       PCP_RECURRING_WEEKLY,
00372                                                       &save_time,
00373                                                       &list))
00374                                    usage();
00375                      }
00376                      else
00377                      {
00378                             save_time(from_time, to_time, &list);
00379                      }
00380                      continue;
00381               }
00382 
00383               if (strcmp(argv[argn], "subject") == 0)
00384               {
00385                      if (subject || ++argn >= argc)
00386                             usage();
00387                      subject=argv[argn++];
00388                      continue;
00389               }
00390               usage();
00391        }
00392 
00393        memset(&commit_info, 0, sizeof(commit_info));
00394        commit_info.flags=flags;
00395 
00396        {
00397               struct event_time_list *p;
00398               struct PCP_event_time *q=0;
00399 
00400               for (p=list; p; p=p->next)
00401                      ++commit_info.n_event_times;
00402 
00403               if (!commit_info.n_event_times)
00404                      usage();
00405 
00406               if ((commit_info.event_times=q=
00407                    calloc(commit_info.n_event_times,
00408                          sizeof(*commit_info.event_times))) == NULL)
00409               {
00410                      perror("malloc");
00411                      exit(1);
00412               }
00413               commit_info.n_event_times=0;
00414               for (p=list; p; p=p->next)
00415                      q[commit_info.n_event_times++]=p->thetime;
00416        }
00417 
00418        memset(&add_event_info, 0, sizeof(add_event_info));
00419        {
00420               struct participant_list *p;
00421               struct PCP_event_participant *q=0;
00422 
00423               for (p=book; p; p=p->next)
00424                      ++add_event_info.n_event_participants;
00425 
00426               if (add_event_info.n_event_participants &&
00427                   (add_event_info.event_participants=q=
00428                    calloc(add_event_info.n_event_participants,
00429                          sizeof(*add_event_info.event_participants)))
00430                   == NULL)
00431               {
00432                      perror("malloc");
00433                      exit(1);
00434                      return;
00435               }
00436               add_event_info.n_event_participants=0;
00437 
00438               for (p=book; p; p=p->next)
00439                      q[add_event_info.n_event_participants++]
00440                             =p->participant;
00441        }
00442 
00443        add_event_info.write_event_func=add_info_callback;
00444        add_event_info.write_event_func_misc_ptr=add_info;
00445 
00446        pcp=open_calendar();
00447 
00448        nei=pcp_new_eventid(pcp, old, &add_event_info);
00449 
00450        if (!nei)
00451        {
00452               pcp_close(pcp);
00453               perror("pcp_new_event_id");
00454               exit(1);
00455        }
00456 
00457        commit_info.add_conflict_callback= &show_conflict;
00458        if (pcp_commit(pcp, nei, &commit_info))
00459        {
00460               error(pcp, commit_info.errcode, "pcp_commit");
00461               pcp_destroy_eventid(pcp, nei);
00462               pcp_close(pcp);
00463               exit(1);
00464        }
00465 
00466        printf(gettext("Created event %s\n"), nei->eventid);
00467        pcp_destroy_eventid(pcp, nei);
00468        pcp_close(pcp);
00469        exit (0);
00470 }
00471 
00472 static int add_info_callback(char *buf, int cnt, void *p)
00473 {
00474        struct add_info *ai=(struct add_info *)p;
00475        int n;
00476 
00477        if (!ai->bufleft)
00478        {
00479               n= (*ai->add_func)(ai);
00480 
00481               if (n < 0)
00482                      return (n);
00483        }
00484        n=0;
00485        while (cnt && ai->bufleft)
00486        {
00487               *buf++ = *ai->bufptr++;
00488               --ai->bufleft;
00489               --cnt;
00490               ++n;
00491        }
00492        return (n);
00493 }
00494 
00495 static int add_read_stdin(struct add_info *p)
00496 {
00497        int n=read(0, p->buffer, sizeof(p->buffer));
00498 
00499        p->bufptr=p->buffer;
00500        if (n < 0)
00501               return (n);
00502        p->bufleft=n;
00503        return (0);
00504 }
00505 
00506 static int add_read_stdin_prompt(struct add_info *p)
00507 {
00508        p->add_func=add_read_stdin;
00509 
00510        printf(gettext("\nEnter event information, terminate with EOF (usually CTRL-D)\n\n"));
00511        return (add_read_stdin(p));
00512 }
00513 
00514 static int add_read_mime(struct add_info *p);
00515 
00516 static int add_read_subject(struct add_info *p)
00517 {
00518        strcpy(p->buffer, "Subject: ");
00519        strncat(p->buffer, p->add_subject, sizeof(p->buffer)-100);
00520        strcat(p->buffer, "\n");
00521        p->add_func= &add_read_mime;
00522        p->bufptr=p->buffer;
00523        p->bufleft=strlen(p->buffer);
00524        return (0);
00525 }
00526 
00527 static int add_read_mime(struct add_info *p)
00528 {
00529        strcpy(p->buffer, "Mime-Version: 1.0\n"
00530               "Content-Type: text/plain; charset=\"");
00531        strcat(p->buffer, p->add_charset);
00532        strcat(p->buffer, "\"\nContent-Transfer-Encoding: 8bit\n\n");
00533        p->add_func= add_read_stdin_prompt;
00534        p->bufptr=p->buffer;
00535        p->bufleft=strlen(p->buffer);
00536        return (0);
00537 }
00538 
00539 /**** List calendar ****/
00540 
00541 static int list_callback_saveindex(struct PCP_list_all *, void *);
00542 
00543 struct listinfo {
00544        time_t list_from;
00545        time_t list_to;
00546        const char *list_event_id;
00547        int cnt;
00548        struct listinfo_index *index_list;
00549        unsigned i_cnt;
00550 } ;
00551 
00552 struct listinfo_index {
00553        struct listinfo_index *next;
00554        size_t from;
00555        size_t to;
00556        char *subject;
00557        char *eventid;
00558        int status;
00559 } ;
00560 
00561 static int indexcmp(const void *a, const void *b)
00562 {
00563        struct listinfo_index *ap=*(struct listinfo_index * const *)a;
00564        struct listinfo_index *bp=*(struct listinfo_index * const *)b;
00565 
00566        return ( ap->from < bp->from ? -1:
00567                ap->from > bp->from ? 1:
00568                ap->to < bp->to ? -1:
00569                ap->to > bp->to ? 1:0);
00570 }
00571 
00572 static void doretr(const char *);
00573 
00574 static int save_retr_headers(struct PCP_retr *, const char *,
00575                           const char *, void *);
00576 static int save_retr_status(struct PCP_retr *, int, void *);
00577 
00578 static void dump_rfc822_hdr(const char *ptr, size_t cnt,
00579                          void *dummy)
00580 {
00581        fwrite(ptr, cnt, 1, stdout);
00582 }
00583 
00584 
00585 static void list(int argn, int argc, char **argv, int flags)
00586 {
00587        struct listinfo listinfo;
00588        int all_flag=0;
00589        struct PCP *pcp;
00590        struct PCP_list_all list_all;
00591 
00592        memset(&listinfo, 0, sizeof(listinfo));
00593        memset(&list_all, 0, sizeof(list_all));
00594 
00595        while (argn < argc)
00596        {
00597               if (strcasecmp(argv[argn], gettext("all")) == 0)
00598               {
00599                      all_flag=1;
00600                      ++argn;
00601                      continue;
00602               }
00603 
00604               if (strcasecmp(argv[argn], on_s()) == 0)
00605               {
00606                      ++argn;
00607                      if (listinfo.list_from ||
00608                          listinfo.list_to ||
00609                          (listinfo.list_from=
00610                           listinfo.list_to=
00611                           parse_datetime(&argn, argc, argv)) == 0)
00612                             usage();
00613                      continue;
00614               }
00615 
00616               if (strcasecmp(argv[argn], from_s()) == 0)
00617               {
00618                      ++argn;
00619                      if (listinfo.list_from != 0 ||
00620                          (listinfo.list_from=
00621                           parse_datetime(&argn, argc, argv)) == 0)
00622                             usage();
00623                      continue;
00624               }
00625 
00626               if (strcasecmp(argv[argn], to_s()) == 0)
00627               {
00628                      ++argn;
00629                      if (listinfo.list_to != 0 ||
00630                          (listinfo.list_to=
00631                           parse_datetime(&argn, argc, argv)) == 0)
00632                             usage();
00633                      continue;
00634               }
00635 
00636               if (strcasecmp(argv[argn], event_s()) == 0)
00637               {
00638                      ++argn;
00639                      if (argn >= argc || listinfo.list_event_id)
00640                             usage();
00641                      listinfo.list_event_id=argv[argn++];
00642                      continue;
00643               }
00644               usage();
00645        }
00646 
00647        /* If neither start-end, nor "all" is specified, list events
00648           for today */
00649 
00650        if (!all_flag && listinfo.list_from == 0 &&
00651            listinfo.list_to == 0 && !listinfo.list_event_id)
00652        {
00653               time_t t;
00654               struct tm *tmptr;
00655 
00656               time(&t);
00657               tmptr=localtime(&t);
00658 
00659               pcp_parse_ymd(tmptr->tm_year + 1900,
00660                            tmptr->tm_mon + 1,
00661                            tmptr->tm_mday,
00662                            &listinfo.list_from,
00663                            &listinfo.list_to);
00664        }
00665 
00666        if ((listinfo.list_from || listinfo.list_to)
00667            && listinfo.list_event_id)
00668        usage();
00669 
00670        if (listinfo.list_event_id)
00671        {
00672               doretr(listinfo.list_event_id);
00673               return;
00674        }
00675 
00676        pcp=open_calendar();
00677 
00678        list_all.callback_func=list_callback_saveindex;
00679        list_all.callback_arg= &listinfo;
00680        list_all.list_from=listinfo.list_from;
00681        list_all.list_to=listinfo.list_to;
00682        listinfo.i_cnt=0;
00683        if (pcp_list_all(pcp, &list_all))
00684        {
00685               perror("pcp_xlist");
00686               pcp_close(pcp);
00687               exit(1);
00688        }
00689 
00690        /* Show event index */
00691 
00692        if (listinfo.index_list)
00693        {
00694               unsigned cnt=0, i, maxl;
00695               struct listinfo_index *p, **ary;
00696               const char **event_id_list;
00697               struct PCP_retr r;
00698 
00699               for (p=listinfo.index_list; p; p=p->next)
00700                      ++cnt;
00701 
00702               event_id_list=(const char **)
00703                      malloc(sizeof(const char *)*(cnt+1));
00704               if (!event_id_list)
00705               {
00706                      perror("malloc");
00707                      exit(1);
00708               }
00709               cnt=0;
00710 
00711               for (p=listinfo.index_list; p; p=p->next)
00712                      event_id_list[cnt++]=p->eventid;
00713               event_id_list[cnt]=0;
00714               memset(&r, 0, sizeof(r));
00715               r.callback_arg=&listinfo;
00716 
00717               r.callback_retr_status=save_retr_status;
00718               r.callback_arg=&listinfo;
00719               r.event_id_list=event_id_list;
00720 
00721               if (pcp_retr(pcp, &r))
00722               {
00723                      error(pcp, r.errcode, "pcp_retr");
00724                      pcp_close(pcp);
00725                      exit(1);
00726               }
00727 
00728               r.callback_headers_func=save_retr_headers;
00729 
00730               if (pcp_retr(pcp, &r))
00731               {
00732                      error(pcp, r.errcode, "pcp_retr");
00733                      pcp_close(pcp);
00734                      exit(1);
00735               }
00736 
00737               free(event_id_list);
00738 
00739               ary=(struct listinfo_index **)
00740                      malloc(sizeof(struct listinfo_index *)
00741                             * listinfo.i_cnt);
00742 
00743               if (!ary)
00744               {
00745                      perror("malloc");
00746                      pcp_close(pcp);
00747                      exit(1);
00748               }
00749 
00750               cnt=0;
00751               for (p=listinfo.index_list; p; p=p->next)
00752                      ary[cnt++]=p;
00753               qsort(ary, cnt, sizeof(ary[0]), indexcmp);
00754 
00755               maxl=20;
00756 
00757               for (i=0; i<cnt; i++)
00758               {
00759                      char fromto[500];
00760 
00761                      if (pcp_fmttimerange(fromto, sizeof(fromto),
00762                                         ary[i]->from,
00763                                         ary[i]->to) == 0 &&
00764                          strlen(fromto) > maxl)
00765                             maxl=strlen(fromto);
00766               }
00767 
00768               for (i=0; i<cnt; i++)
00769               {
00770                      char fromto[500];
00771 
00772                      if (pcp_fmttimerange(fromto, sizeof(fromto),
00773                                         ary[i]->from,
00774                                         ary[i]->to) < 0)
00775                             strcpy(fromto, "******");
00776                      printf("%-*s %s%s", (int)maxl, fromto,
00777                             ary[i]->status & LIST_CANCELLED
00778                             ? gettext("CANCELLED: "):"",
00779                             ary[i]->status & LIST_BOOKED
00780                             ? gettext("(event not yet commited) "):"");
00781 
00782                      if (rfc822_display_hdrvalue("subject",
00783                                               ary[i]->subject
00784                                               ? ary[i]->subject:"",
00785                                               charset,
00786                                               dump_rfc822_hdr,
00787                                               NULL, NULL) < 0)
00788                      {
00789                             printf("%s", 
00790                                    ary[i]->subject
00791                                    ? ary[i]->subject:"");
00792                      }
00793                      printf("\n");
00794 
00795                      if (flags & FLAG_LIST_EVENT_ID)
00796                             printf("%-*s(%s)\n", (int)maxl, "",
00797                                    ary[i]->eventid);
00798               }
00799               free(ary);
00800               listinfo.cnt=cnt;
00801        }
00802 
00803        printf(gettext("%d events found.\n"), listinfo.cnt);
00804 
00805        while (listinfo.index_list)
00806        {
00807               struct listinfo_index *p=listinfo.index_list;
00808 
00809               listinfo.index_list=p->next;
00810               free(p->eventid);
00811               if (p->subject)
00812                      free(p->subject);
00813               free(p);
00814        }
00815        pcp_close(pcp);
00816 }
00817 
00818 static int list_callback_saveindex(struct PCP_list_all *xl, void *vp)
00819 {
00820        struct listinfo *li=(struct listinfo *)vp;
00821        struct listinfo_index *i;
00822 
00823        li->cnt++;
00824 
00825        if ((i=(struct listinfo_index *)
00826             malloc(sizeof(struct listinfo_index))) == NULL)
00827        {
00828               perror("malloc");
00829               exit(1);
00830        }
00831        memset(i, 0, sizeof(*i));
00832 
00833        if ((i->eventid=strdup(xl->event_id)) == NULL)
00834        {
00835               free(i);
00836               perror("malloc");
00837               exit(1);
00838        }
00839 
00840        i->next=li->index_list;
00841        li->index_list=i;
00842        ++li->i_cnt;
00843        i->from=xl->event_from;
00844        i->to=xl->event_to;
00845        i->subject=NULL;
00846        return (0);
00847 }
00848 
00849 static int save_retr_status(struct PCP_retr *r, int status, void *vp)
00850 {
00851        struct listinfo *l=(struct listinfo *)vp;
00852        struct listinfo_index *i;
00853 
00854        for (i=l->index_list; i; i=i->next)
00855               if (strcmp(i->eventid, r->event_id) == 0)
00856               {
00857                      i->status=status;
00858               }
00859        return (0);
00860 }
00861 
00862 static int save_retr_headers(struct PCP_retr *ri, const char *h,
00863                           const char *v, void *vp)
00864 {
00865        struct listinfo *l=(struct listinfo *)vp;
00866        struct listinfo_index *i;
00867        char *p, *q;
00868 
00869        if (strcasecmp(h, "subject"))
00870               return (0);
00871 
00872        for (i=l->index_list; i; i=i->next)
00873               if (strcmp(i->eventid, ri->event_id) == 0)
00874               {
00875                      if (!i->subject)
00876                      {
00877                             i->subject=strdup(v);
00878                             if (!i->subject)
00879                                    return (-1);
00880                      }
00881 
00882                      for (p=q=i->subject; *p; )
00883                      {
00884                             if (*p == '\n')
00885                             {
00886                                    while (*p && isspace((int)
00887                                                       (unsigned char)
00888                                                       *p))
00889                                           ++p;
00890                                    *q++=' ';
00891                                    continue;
00892                             }
00893                             *q++ = *p++;
00894                      }
00895                      *q=0;
00896               }
00897        return (0);
00898 }
00899 
00900 static int doretr_begin(struct PCP_retr *r, void *vp);
00901 static int doretr_save(struct PCP_retr *, const char *, int, void *);
00902 static int do_show_retr(struct PCP_retr *, void *);
00903 
00904 struct xretrinfo {
00905        FILE *tmpfile;
00906        int status;
00907        struct xretr_participant_list *participant_list;
00908        struct xretr_time_list *time_list;
00909 
00910 } ;
00911 
00912 struct xretr_participant_list {
00913        struct xretr_participant_list *next;
00914        char *participant;
00915 } ;
00916 
00917 struct xretr_time_list {
00918        struct xretr_time_list *next;
00919        time_t from;
00920        time_t to;
00921 } ;
00922 
00923 static int doretr_status(struct PCP_retr *p, int status, void *vp)
00924 {
00925        struct xretrinfo *xr=(struct xretrinfo *)vp;
00926 
00927        xr->status=status;
00928        return (0);
00929 }
00930 
00931 static int doretr_date(struct PCP_retr *p, time_t from, time_t to, void *vp)
00932 {
00933        struct xretrinfo *xr=(struct xretrinfo *)vp;
00934        struct xretr_time_list *t=malloc(sizeof(struct xretr_time_list));
00935 
00936        if (!t)
00937               return (-1);
00938 
00939        t->next=xr->time_list;
00940        xr->time_list=t;
00941        t->from=from;
00942        t->to=to;
00943        return (0);
00944 }
00945 
00946 static int doretr_participants(struct PCP_retr *p, const char *n,
00947                             const char *id, void *vp)
00948 {
00949        struct xretrinfo *xr=(struct xretrinfo *)vp;
00950        char *s=strdup(n);
00951        struct xretr_participant_list *pa;
00952 
00953        if (!s)
00954               return (-1);
00955 
00956        if ((pa=malloc(sizeof(struct xretr_participant_list))) == NULL)
00957        {
00958               free(s);
00959               return (-1);
00960        }
00961        pa->participant=s;
00962        pa->next=xr->participant_list;
00963        xr->participant_list=pa;
00964        return (0);
00965 }
00966 
00967 static void doretr(const char *eventid)
00968 {
00969        struct PCP *pcp;
00970        struct PCP_retr r;
00971        struct xretrinfo xr;
00972        const char *event_id_array[2];
00973        struct xretr_time_list *tl;
00974        struct xretr_participant_list *pl;
00975 
00976        pcp=open_calendar();
00977 
00978        memset(&r, 0, sizeof(r));
00979        memset(&xr, 0, sizeof(xr));
00980 
00981        r.callback_arg= &xr;
00982        r.callback_retr_status=doretr_status;
00983        r.callback_retr_date=doretr_date;
00984        r.callback_retr_participants=doretr_participants;
00985 
00986        event_id_array[0]=eventid;
00987        event_id_array[1]=NULL;
00988 
00989        r.event_id_list=event_id_array;
00990 
00991        if (pcp_retr(pcp, &r) == 0)
00992        {
00993               r.callback_retr_status=NULL;
00994               r.callback_retr_date=NULL;
00995               r.callback_retr_participants=NULL;
00996 
00997               r.callback_begin_func=doretr_begin;
00998               r.callback_rfc822_func=doretr_save;
00999               r.callback_end_func=do_show_retr;
01000               if (pcp_retr(pcp, &r) == 0)
01001               {
01002                      pcp_close(pcp);
01003               }
01004               else
01005               {
01006                      error(pcp, r.errcode, "pcp_retr");
01007                      pcp_close(pcp);
01008               }
01009        }
01010        else
01011        {
01012               error(pcp, r.errcode, "pcp_retr");
01013               pcp_close(pcp);
01014        }
01015 
01016        while ((pl=xr.participant_list) != NULL)
01017        {
01018               xr.participant_list=pl->next;
01019               free(pl->participant);
01020               free(pl);
01021        }
01022 
01023        while ((tl=xr.time_list) != NULL)
01024        {
01025               xr.time_list=tl->next;
01026               free(tl);
01027        }
01028 }
01029 
01030 static int doretr_begin(struct PCP_retr *r, void *vp)
01031 {
01032        struct xretrinfo *xr=(struct xretrinfo *)vp;
01033 
01034        if ((xr->tmpfile=tmpfile()) == NULL)
01035               return (-1);
01036        return (0);
01037 }
01038 
01039 static int doretr_save(struct PCP_retr *r, const char *p, int n, void *vp)
01040 {
01041        struct xretrinfo *xr=(struct xretrinfo *)vp;
01042 
01043        if (fwrite(p, n, 1, xr->tmpfile) != 1)
01044               return (-1);
01045        return (0);
01046 }
01047 
01048 static int tcmp(const void *a, const void *b)
01049 {
01050        struct xretr_time_list *ap=*(struct xretr_time_list **)a;
01051        struct xretr_time_list *bp=*(struct xretr_time_list **)b;
01052 
01053        return ( ap->from < bp->from ? -1:
01054                ap->from > bp->from ? 1:
01055                ap->to < bp->to ? -1:
01056                ap->to > bp->to ? 1:0);
01057 }
01058 
01059 static int list_msg_rfc822(struct rfc2045 *, FILE *);
01060 
01061 static int do_show_retr(struct PCP_retr *r, void *vp)
01062 {
01063        struct xretrinfo *xr=(struct xretrinfo *)vp;
01064        struct xretr_participant_list *p;
01065        struct xretr_time_list *t, **tt;
01066        unsigned cnt, i;
01067        struct rfc2045 *rfcp;
01068        int rc;
01069 
01070        if (fseek(xr->tmpfile, 0L, SEEK_SET) < 0
01071            || lseek(fileno(xr->tmpfile), 0L, SEEK_SET) < 0)
01072        {
01073               fclose(xr->tmpfile);
01074               return (-1);
01075        }
01076 
01077        if (xr->time_list == NULL)
01078        {
01079               fclose(xr->tmpfile);
01080               return (0);
01081        }
01082 
01083        printf(gettext("Event: %s\n"), r->event_id);
01084 
01085        for (cnt=0, t=xr->time_list; t; t=t->next)
01086               ++cnt;
01087 
01088        tt=(struct xretr_time_list **)malloc(cnt * sizeof(*t));
01089        if (!tt)
01090        {
01091               fclose(xr->tmpfile);
01092               return (-1);
01093        }
01094 
01095        for (cnt=0, t=xr->time_list; t; t=t->next)
01096               tt[cnt++]=t;
01097 
01098        qsort(tt, cnt, sizeof(*tt), tcmp);
01099 
01100        for (i=0; i<cnt; i++)
01101        {
01102               char fromto[500];
01103 
01104               if (pcp_fmttimerange(fromto, sizeof(fromto),
01105                                  tt[i]->from, tt[i]->to) < 0)
01106                      strcpy(fromto, "******");
01107               printf(gettext("       %s\n"), fromto);
01108        }
01109        free(tt);
01110 
01111        if (xr->status & LIST_CANCELLED)
01112               printf(gettext("    **** CANCELLED ****\n"));
01113        if (xr->status & LIST_BOOKED)
01114               printf(gettext("    **** EVENT NOT YET COMMITED ****\n"));
01115 
01116        for (p=xr->participant_list; p; p=p->next)
01117               printf(gettext("    Participant: %s\n"), p->participant);
01118 
01119 
01120        rfcp=rfc2045_fromfp(xr->tmpfile);
01121        if (!rfcp)
01122        {
01123               fclose(xr->tmpfile);
01124               return (-1);
01125        }
01126 
01127        rc=list_msg_rfc822(rfcp, xr->tmpfile);
01128        rfc2045_free(rfcp);
01129        fclose(xr->tmpfile);
01130        return (rc);
01131 }
01132 
01133 static int list_msg_mime(struct rfc2045 *, FILE *);
01134 
01135 static int list_msg_rfc822(struct rfc2045 *rfc, FILE *fp)
01136 {
01137        off_t   start_pos, end_pos, start_body;
01138        off_t  dummy, pos;
01139        struct rfc822hdr h;
01140 
01141         rfc2045_mimepos(rfc, &start_pos, &end_pos, &start_body,
01142                      &dummy, &dummy);
01143         if (fseek(fp, start_pos, SEEK_SET) < 0)
01144               return (-1);
01145 
01146        pos=start_pos;
01147        rfc822hdr_init(&h, 8192);
01148 
01149        while (rfc822hdr_read(&h, fp, &pos, start_body) == 0)
01150        {
01151               printf("%s: ", h.header);
01152 
01153               if (rfc822_display_hdrvalue(h.header, h.value, charset,
01154                                        dump_rfc822_hdr, NULL, NULL) < 0)
01155               {
01156                      printf("%s", h.value);
01157               }
01158 
01159               printf("\n");
01160        }
01161        rfc822hdr_free(&h);
01162        printf("\n");
01163        return (list_msg_mime(rfc, fp));
01164 }
01165 
01166 static int list_msg_rfc822_part(struct rfc2045 *rfc, FILE *fp)
01167 {
01168        struct rfc2045 *q;
01169 
01170        for (q=rfc->firstpart; q; q=q->next)
01171        {
01172               if (q->isdummy) continue;
01173               return (list_msg_rfc822(q, fp));
01174        }
01175        return (0);
01176 }
01177 
01178 
01179 static int list_msg_mime_multipart(struct rfc2045 *, FILE *);
01180 static int list_msg_mime_multipart_alternative(struct rfc2045 *, FILE *);
01181 static int list_msg_textplain(struct rfc2045 *, FILE *);
01182 
01183 static int (*mime_handler(struct rfc2045 *rfc))(struct rfc2045 *, FILE *)
01184 {
01185        const char      *content_type, *dummy;
01186 
01187         rfc2045_mimeinfo(rfc, &content_type, &dummy, &dummy);
01188         if (strcmp(content_type, "multipart/alternative") == 0)
01189               return ( &list_msg_mime_multipart_alternative);
01190         if (strncmp(content_type, "multipart/", 10) == 0)
01191               return ( &list_msg_mime_multipart);
01192 
01193         if (strcmp(content_type, "message/rfc822") == 0)
01194               return ( &list_msg_rfc822_part );
01195 
01196         if (strcmp(content_type, "text/plain") == 0
01197            || strcmp(content_type, "text/rfc822-headers") == 0
01198            || strcmp(content_type, "message/delivery-status") == 0)
01199               return ( &list_msg_textplain);
01200        return (NULL);
01201 }
01202 
01203 
01204 static int list_msg_mime(struct rfc2045 *rfc, FILE *fp)
01205 {
01206        int (*handler)(struct rfc2045 *, FILE *)=
01207               mime_handler(rfc);
01208        const char      *content_type, *dummy;
01209 
01210 
01211        char *disposition_name;
01212        char *disposition_filename;
01213        char *content_name;
01214 
01215        const char *disposition_filename_s;
01216 
01217        off_t start_pos, end_pos, start_body;
01218        off_t dummy2;
01219        char buffer[NUMBUFSIZE+10];
01220 
01221        if (handler)
01222               return ( (*handler)(rfc, fp));
01223 
01224         rfc2045_mimeinfo(rfc, &content_type, &dummy, &dummy);
01225 
01226        if (rfc2231_udecodeDisposition(rfc, "name", NULL, &disposition_name)<0)
01227               disposition_name=NULL;
01228 
01229        if (rfc2231_udecodeDisposition(rfc, "filename", NULL,
01230                                    &disposition_filename) < 0)
01231               disposition_filename=NULL;
01232 
01233        if (rfc2231_udecodeType(rfc, "name", NULL, &content_name) < 0)
01234               content_name=NULL;
01235 
01236         rfc2045_mimepos(rfc, &start_pos, &end_pos, &start_body,
01237                         &dummy2, &dummy2);
01238 
01239        disposition_filename_s=disposition_filename;
01240 
01241        if (!disposition_filename_s || !*disposition_filename_s)
01242               disposition_filename_s=disposition_name;
01243        if (!disposition_filename_s || !*disposition_filename_s)
01244               disposition_filename_s=content_name;
01245 
01246        printf(gettext("Attachment: %s (%s)\n"), content_type,
01247               libmail_str_sizekb(end_pos - start_body, buffer));
01248        if (disposition_filename_s && *disposition_filename_s)
01249               printf("    %s\n", disposition_filename_s);
01250        printf("\n");
01251 
01252        if (content_name)           free(content_name);
01253        if (disposition_name)              free(disposition_name);
01254        if (disposition_filename)   free(disposition_filename);
01255 
01256        return (0);
01257 }
01258 
01259 static int list_msg_mime_multipart(struct rfc2045 *rfc, FILE *fp)
01260 {
01261        struct rfc2045 *q;
01262        int first=1;
01263        int rc;
01264 
01265        for (q=rfc->firstpart; q; q=q->next)
01266        {
01267               if (q->isdummy) continue;
01268 
01269               if (!first)
01270                      printf("\n    ------------------------------\n\n");
01271               first=0;
01272 
01273               rc=list_msg_mime(q, fp);
01274               if (rc)
01275                      return (rc);
01276        }
01277        return (0);
01278 }
01279 
01280 static int list_msg_mime_multipart_alternative(struct rfc2045 *rfc, FILE *fp)
01281 {
01282        struct rfc2045 *q, *first=NULL, *last=NULL;
01283 
01284        for (q=rfc->firstpart; q; q=q->next)
01285        {
01286               if (q->isdummy) continue;
01287               if (!first)
01288                      first=q;
01289               if ( mime_handler(q) != NULL)
01290                      last=q;
01291        }
01292 
01293        return (last ? list_msg_mime(last, fp):
01294               first ? list_msg_mime(first, fp):0);
01295 }
01296 
01297 static int textplain_output(const char *ptr, size_t cnt, void *voidptr)
01298 {
01299        while (cnt)
01300        {
01301               putchar(*ptr);
01302               ++ptr;
01303               --cnt;
01304        }
01305        return (0);
01306 }
01307 
01308 static int list_msg_textplain(struct rfc2045 *rfc, FILE *fp)
01309 {
01310        const char *mime_charset, *dummy;
01311        int rc;
01312        struct rfc2045src *src;
01313 
01314         rfc2045_mimeinfo(rfc, &dummy, &dummy, &mime_charset);
01315 
01316         if (strcasecmp(mime_charset, charset))
01317         {
01318               printf(gettext("    (The following text was converted from %s)\n\n"),
01319                      mime_charset);
01320        }
01321 
01322        src=rfc2045src_init_fd(fileno(fp));
01323 
01324        if (src == NULL)
01325               return (-1);
01326 
01327        rc=rfc2045_decodetextmimesection(src,
01328                                     rfc,
01329                                     charset,
01330                                     NULL,
01331                                     textplain_output, NULL);
01332 
01333        printf("\n");
01334        rfc2045src_deinit(src);
01335        return (rc);
01336 }
01337 
01338 /*** CANCEL/UNCANCEL/DELETE ***/
01339 
01340 static void docancel(const char *id, int flags)
01341 {
01342        struct PCP *pcp=open_calendar();
01343        int errcode;
01344 
01345        if (pcp_cancel(pcp, id, &errcode))
01346        {
01347               error(pcp, errcode, "pcp_cancel");
01348               exit(1);
01349        }
01350        pcp_close(pcp);
01351 }
01352 
01353 static void dodelete(const char *id, int flags)
01354 {
01355        struct PCP *pcp=open_calendar();
01356        struct PCP_delete del;
01357 
01358        memset(&del, 0, sizeof(del));
01359        del.id=id;
01360 
01361        if (pcp_delete(pcp, &del))
01362        {
01363               error(pcp, del.errcode, "pcp_delete");
01364               exit(1);
01365        }
01366        pcp_close(pcp);
01367 }
01368 
01369 static void douncancel(const char *id, int flags)
01370 {
01371        struct PCP *pcp=open_calendar();
01372        struct PCP_uncancel uncancel_info;
01373 
01374        memset(&uncancel_info, 0, sizeof(uncancel_info));
01375        uncancel_info.uncancel_conflict_callback= &show_conflict;
01376        uncancel_info.uncancel_conflict_callback_ptr=NULL;
01377 
01378        if (pcp_uncancel(pcp, id, flags, &uncancel_info))
01379        {
01380               error(pcp, uncancel_info.errcode, "pcp_uncancel");
01381               exit(1);
01382        }
01383        pcp_close(pcp);
01384 }
01385 
01386 /* Initialize */
01387 
01388 static void init(const char *shell)
01389 {
01390        struct passwd *pw=do_getpw();
01391 
01392        if (chdir(pw->pw_dir))
01393        {
01394               perror(pw->pw_dir);
01395               exit(1);
01396        }
01397        unlink(".pcplogin");
01398 }
01399 
01400 /* Login to a server */
01401 
01402 static void login(const char *userid)
01403 {
01404        char *errmsg;
01405        char password[1024];
01406        struct PCP *pcp;
01407        char *p;
01408 
01409 #if HAVE_TCGETATTR
01410        struct termios tios;
01411        int tios_rc=tcgetattr(0, &tios);
01412 
01413        if (tios_rc >= 0)
01414        {
01415               tios.c_lflag &= ~ECHO;
01416               tcsetattr(0, TCSANOW, &tios);
01417        }
01418 #endif
01419 
01420        printf(gettext("Password: "));
01421 
01422        if (fgets(password, sizeof(password), stdin) == NULL)
01423               password[0]=0;
01424 
01425 #if HAVE_TCGETATTR
01426        if (tios_rc >= 0)
01427        {
01428               tios.c_lflag |= ECHO;
01429               tcsetattr(0, TCSANOW, &tios);
01430               printf("\n");
01431        }
01432 #endif
01433 
01434        if ((p=strchr(password, '\n')) != 0)
01435               *p=0;
01436 
01437        pcp=pcp_open_server(userid, password, &errmsg);
01438 
01439        if (pcp)
01440        {
01441               struct passwd *pw=do_getpw();
01442               FILE *fp;
01443               const char *p=pcp_authtoken(pcp);
01444 
01445               if (!p)
01446               {
01447                      fprintf(stderr, gettext("ERROR: Unable to obtain authentication token from the server.\n"));
01448                      exit(1);
01449               }
01450 
01451               if (chdir(pw->pw_dir) < 0)
01452               {
01453                      perror(pw->pw_dir);
01454                      exit(1);
01455               }
01456               umask(077);
01457               fp=fopen(".pcplogin", "w");
01458 
01459               if (!fp)
01460               {
01461                      perror("$HOME/.pcplogin");
01462                      exit(1);
01463               }
01464 
01465               fprintf(fp, "%s\n%s\n", userid, p);
01466               if (fflush(fp) < 0 || ferror(fp) || fclose(fp))
01467               {
01468                      perror("$HOME/.pcplogin");
01469                      unlink(".pcplogin");
01470                      exit(1);
01471               }
01472               pcp_close(pcp);
01473               return;
01474        }
01475 
01476        printf(gettext("ERROR:\n%s\n"), errmsg ? errmsg:strerror(errno));
01477        if (errmsg)
01478               free(errmsg);
01479 }
01480 
01481 /* setacl */
01482 
01483 static void setacl(const char *who, int flags)
01484 {
01485        struct PCP *pcp=open_calendar();
01486 
01487        if (pcp_has_acl(pcp))
01488        {
01489               if (pcp_acl(pcp, who, flags))
01490               {
01491                      error(pcp, 0, "pcp_acl");
01492                      exit(1);
01493               }
01494        }
01495        else
01496        {
01497               fprintf(stderr, gettext("ERROR: ACLs not supported.\n"));
01498        }
01499        pcp_close(pcp);
01500 }
01501 
01502 static int do_list_acl(const char *who, int flags, void *dummy)
01503 {
01504        char buf[1024];
01505 
01506        buf[0]=0;
01507        pcp_acl_name(flags, buf);
01508 
01509        printf("%-30s\t%s\n", who, buf);
01510        return (0);
01511 }
01512 
01513 static void listacls()
01514 {
01515        struct PCP *pcp=open_calendar();
01516 
01517        if (pcp_has_acl(pcp))
01518        {
01519               if (pcp_list_acl(pcp, do_list_acl, NULL))
01520               {
01521                      error(pcp, 0, "pcp_list_acl");
01522                      exit(1);
01523               }
01524        }
01525        else
01526        {
01527               fprintf(stderr, gettext("ERROR: ACLs not supported.\n"));
01528        }
01529        pcp_close(pcp);
01530 }
01531 
01532 /* Connect to a PCP server */
01533 
01534 static int doconnect(const char *pathname)
01535 {
01536         int     fd=socket(PF_UNIX, SOCK_STREAM, 0);
01537         struct  sockaddr_un skun;
01538 
01539        skun.sun_family=AF_UNIX;
01540         strcpy(skun.sun_path, pathname);
01541 
01542        if (fd >= 0 && fcntl(fd, F_SETFL, O_NONBLOCK) >= 0)
01543        {
01544               if (connect(fd, (struct sockaddr *)&skun, sizeof(skun)) == 0)
01545                      return (fd);
01546 
01547               if (errno == EINPROGRESS || errno == EWOULDBLOCK)
01548               {
01549                      struct timeval tv;
01550                      fd_set fds;
01551                      int rc;
01552 
01553                      tv.tv_sec=10;
01554                      tv.tv_usec=0;
01555                      FD_ZERO(&fds);
01556                      FD_SET(fd, &fds);
01557 
01558                      rc=select(fd+1, NULL, &fds, NULL, &tv);
01559 
01560                      if (rc > 1 && FD_ISSET(fd, &fds))
01561                      {
01562                             if (connect(fd, (struct sockaddr *)&skun,
01563                                        sizeof(skun)) == 0)
01564                                    return (fd);
01565                             if (errno == EISCONN)
01566                                    return (fd);
01567                      }
01568 
01569                      if (rc >= 0)
01570                             errno=ETIMEDOUT;
01571               }
01572        }
01573        perror(pathname);
01574        exit(1);
01575        return (0);
01576 }
01577 
01578 static void doconnectwrite(int, const char *, int);
01579 
01580 static void doconnectloop(int fd)
01581 {
01582        char buf[BUFSIZ];
01583        fd_set rfd;
01584 
01585        for (;;)
01586        {
01587               FD_ZERO(&rfd);
01588               FD_SET(0, &rfd);
01589               FD_SET(fd, &rfd);
01590 
01591               if (select(fd+1, &rfd, NULL, NULL, NULL) <= 0)
01592               {
01593                      perror("select");
01594                      continue;
01595               }
01596 
01597               if (FD_ISSET(fd, &rfd))
01598               {
01599                      int n=read(fd, buf, sizeof(buf));
01600 
01601                      if (n < 0)
01602                             perror("read");
01603                      if (n <= 0)
01604                             break;
01605                      doconnectwrite(1, buf, n);
01606               }
01607 
01608               if (FD_ISSET(0, &rfd))
01609               {
01610                      int n=read(0, buf, sizeof(buf));
01611 
01612                      if (n < 0)
01613                             perror("read");
01614                      if (n <= 0)
01615                             break;
01616                      doconnectwrite(fd, buf, n);
01617               }
01618        }
01619        exit(0);
01620 }
01621 
01622 static void doconnectwrite(int fd, const char *p, int cnt)
01623 {
01624        while (cnt > 0)
01625        {
01626               int n=write(fd, p, cnt);
01627 
01628               if (n <= 0)
01629                      exit(0);
01630 
01631               p += n;
01632               cnt -= n;
01633        }
01634 }
01635 
01636 static void usage()
01637 {
01638        const char *charset=unicode_default_chset();
01639 
01640        fprintf(stderr,
01641               gettext("Usage: pcp [options] [command]\n"
01642                      "\n"
01643                      "Options:\n"
01644                      "   -c           - add/uncancel event that conflicts with an existing event\n"
01645                      "   -s subject   - specify event subject\n"
01646                      "   -C charset   - specify your local charset (default %s)\n"
01647                      "   -m           - standard input is already a MIME-formatted message\n"
01648                      "   -e           - list event ids\n"
01649                      "\n"), charset);
01650 
01651        fprintf(stderr, "%s",
01652               gettext(
01653                      "Commands:\n"
01654                      "   init\n"
01655                      "   login USERID\n"
01656                      "   logout\n"
01657                      "   add from FROM to TO [ from FROM to TO...]\n"
01658                      "   update ID from FROM to TO [ from FROM to TO...]\n"
01659                      "   list [all] [from FROM] [to TO] [event ID]\n"
01660                      "   cancel ID\n"
01661                      "   uncancel ID\n"
01662                      "   delete ID\n"
01663                      "   connect [/pathname]\n"
01664                      "   sconnect [/pathname]\n"
01665                      "   setacl [MODIFY|CONFLICT|LIST|RETR|NONE]*\n"
01666                      "   listacl\n"
01667                      ));
01668        exit(1);
01669 }
01670 
01671 static char *read_subject()
01672 {
01673        char buf[BUFSIZ];
01674        char *p;
01675 
01676        printf("Subject: ");
01677 
01678        if (fgets(buf, sizeof(buf), stdin) == NULL)
01679               exit(0);
01680 
01681        p=strchr(buf, '\n');
01682        if (p)
01683               *p=0;
01684 
01685        p=strdup(buf);
01686 
01687        if (!p)
01688        {
01689               perror("malloc");
01690               exit(1);
01691        }
01692        return (p);
01693 }
01694 
01695 static char *mimeify(const char *subject, const char *charset)
01696 {
01697        char *p=rfc2047_encode_str(subject, charset,
01698                                rfc2047_qp_allow_any);
01699 
01700        if (!p)
01701        {
01702               perror("rfc2047_encode_str");
01703               exit(1);
01704        }
01705        return (p);
01706 }
01707 
01708 int main(int argc, char **argv)
01709 {
01710        int flags=0;
01711        int list_flags=0;
01712        int optchar;
01713        const char *subject=0;
01714        int ismime=0;
01715 
01716        setlocale(LC_ALL, "");
01717        textdomain("pcp");
01718 
01719        charset=unicode_default_chset();
01720 
01721        while ((optchar=getopt(argc, argv, "emcs:C:")) >= 0)
01722        {
01723               switch (optchar) {
01724               case 'c':
01725                      flags |= PCP_OK_CONFLICT;
01726                      break;
01727               case 's':
01728                      subject=optarg;
01729                      break;
01730               case 'C':
01731                      charset=optarg;
01732                      break;
01733               case 'm':
01734                      ismime=1;
01735                      break;
01736               case 'e':
01737                      list_flags |= FLAG_LIST_EVENT_ID;
01738                      break;
01739               default:
01740                      usage();
01741               }
01742        }
01743 
01744        if (optind < argc)
01745        {
01746               const char *addstr=gettext("add");
01747               const char *updatestr=gettext("update");
01748 
01749               if (strcmp(argv[optind], gettext("init")) == 0)
01750               {
01751                      ++optind;
01752                      init(optind < argc ? argv[optind]:NULL);
01753                      exit(0);
01754               }
01755               else if (strcmp(argv[optind], gettext("login")) == 0)
01756               {
01757                      ++optind;
01758                      if (optind < argc)
01759                      {
01760                             login(argv[optind]);
01761                             exit (0);
01762                      }
01763               }
01764               else if (strcmp(argv[optind], gettext("connect")) == 0)
01765               {
01766                      int fd;
01767                      const char *n;
01768 
01769                      ++optind;
01770                      n=optind < argc ? argv[optind] : PUBDIR "/50PCPDLOCAL";
01771                      fd=doconnect(n);
01772 
01773                      if (fcntl(fd, F_SETFL, 0) < 0)
01774                      {
01775                             perror(argv[optind]);
01776                             exit (0);
01777                      }
01778                      printf("Connected to %s...\n", n);
01779                      doconnectloop(fd);
01780                      exit (0);
01781               }
01782               else if (strcmp(argv[optind], gettext("sconnect")) == 0)
01783               {
01784                      int fd;
01785                      const char *n;
01786 
01787                      ++optind;
01788                      n=optind < argc ? argv[optind]
01789                             : PRIVDIR "/50PCPDLOCAL";
01790                      fd=doconnect(n);
01791 
01792                      if (fcntl(fd, F_SETFL, 0) < 0)
01793                      {
01794                             perror(argv[optind]);
01795                             exit (0);
01796                      }
01797                      printf("Connected to %s...\n", n);
01798                      doconnectloop(fd);
01799                      exit (0);
01800               }
01801               else if (strcmp(argv[optind], gettext("cancel")) == 0)
01802               {
01803                      ++optind;
01804                      if (optind < argc)
01805                      {
01806                             docancel(argv[optind], flags);
01807                             exit (0);
01808                      }
01809               }
01810               else if (strcmp(argv[optind], gettext("delete")) == 0)
01811               {
01812                      ++optind;
01813                      if (optind < argc)
01814                      {
01815                             dodelete(argv[optind], flags);
01816                             exit (0);
01817                      }
01818               }
01819               else if (strcmp(argv[optind], gettext("uncancel")) == 0)
01820               {
01821                      ++optind;
01822                      if (optind < argc)
01823                      {
01824                             douncancel(argv[optind], flags);
01825                             exit (0);
01826                      }
01827               }
01828               else if (strcmp(argv[optind], addstr) == 0 ||
01829                       strcmp(argv[optind], updatestr) == 0)
01830               {
01831                      struct add_info info;
01832                      const char *oldeventid=0;
01833 
01834                      ++optind;
01835 
01836                      if (strcmp(argv[optind-1], updatestr) == 0)
01837                      {
01838                             if (optind >= argc)
01839                                    usage();
01840                             oldeventid=argv[optind++];
01841                      }
01842 
01843                      memset(&info, 0, sizeof(info));
01844 
01845                      if (ismime)
01846                             info.add_func=add_read_stdin;
01847                      else
01848                      {
01849                             info.add_func=add_read_subject;
01850                             info.add_charset=charset;
01851                             if (subject)
01852                                    info.add_subject=mimeify(subject,
01853                                                          charset);
01854                             else
01855                             {
01856                                    char *p;
01857 
01858                                    if (!isatty(0))
01859                                    {
01860                                           fprintf(stderr,
01861                                                  gettext("Error: -s is required\n"));
01862                                           exit(1);
01863                                    }
01864 
01865                                    p=read_subject();
01866 
01867                                    info.add_subject=mimeify(p, charset);
01868                                    free(p);
01869                             }
01870                      }
01871                      add(optind, argc, argv, flags, oldeventid, &info);
01872                      exit (0);
01873               }
01874               else if (strcmp(argv[optind], gettext("list")) == 0)
01875               {
01876                      list(optind+1, argc, argv, list_flags);
01877                      exit (0);
01878               }
01879               else if (strcmp(argv[optind], gettext("setacl")) == 0)
01880               {
01881                      int flags=0;
01882                      const char *acl;
01883 
01884                      if (++optind < argc)
01885                      {
01886                             acl=argv[optind];
01887 
01888                             while (++optind < argc)
01889                                    flags |= pcp_acl_num(argv[optind]);
01890 
01891                             setacl(acl, flags);
01892                      }
01893                      exit (0);
01894               }
01895               else if (strcmp(argv[optind], gettext("listacl")) == 0)
01896               {
01897                      listacls();
01898                      exit(0);
01899               }
01900        }
01901 
01902        usage();
01903        return (0);
01904 }