Back to index

courier  0.68.2
pcpd.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2001-2006 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 
00007 #include "config.h"
00008 #include "pcp.h"
00009 #include "pcpdtimer.h"
00010 #include <string.h>
00011 #include <stdio.h>
00012 #include <ctype.h>
00013 #include <unistd.h>
00014 #include <stdlib.h>
00015 #include <errno.h>
00016 #include <signal.h>
00017 #include <pwd.h>
00018 #include <grp.h>
00019 #if HAVE_FCNTL_H
00020 #include <fcntl.h>
00021 #endif
00022 #include <sys/types.h>
00023 #include <sys/time.h>
00024 #include <sys/socket.h>
00025 #include <sys/stat.h>
00026 #include <sys/un.h>
00027 #include "liblock/config.h"
00028 #include "liblock/liblock.h"
00029 #include "numlib/numlib.h"
00030 #include "maildir/maildircache.h"
00031 #include "pcpdauth.h"
00032 #include "pcpdauthtoken.h"
00033 #include "calendardir.h"
00034 
00035 PCP_STRERROR
00036 
00037 #define exit(_a_) _exit(_a_)
00038 
00039 static char *userid;
00040 static char *proxy_userid;
00041 static char *deleted_eventid;
00042 static struct PCP_new_eventid *new_eventid;
00043 static int conflict_flag;
00044 static int force_flag;
00045 static int notbooked;
00046 
00047 static struct PCP_commit new_commit;
00048 static struct PCP_event_time *new_commit_times;
00049 static struct PCP_event_participant *new_commit_participants;
00050 static char *new_commit_participants_buf;
00051 
00052 static struct pcpdtimer rebook_timeout;
00053 
00054 static int termsig;
00055 
00056 static int need_rset;
00057 static char *input_buffer=NULL;
00058 static size_t input_buffer_len=0;
00059 static size_t input_line_len;
00060 static time_t prev_time;
00061 static char *inp_ptr;
00062 static int inp_left;
00063 
00064 static void inactive(struct PCP *p, void *dummy)
00065 {
00066        termsig=1;
00067 }
00068 
00069 static int inputchar(struct PCP *pcp)
00070 {
00071        int c;
00072 
00073        while (inp_left == 0)
00074        {
00075               time_t new_time;
00076               struct timeval tv, *tvptr;
00077               fd_set fds;
00078 
00079               time(&new_time);
00080 
00081               /* Trigger any needed functions */
00082 
00083               while (first_timer &&
00084                      (new_time < prev_time - 30 ||
00085                      new_time >= first_timer->alarm))
00086               {
00087                      void (*func)(struct PCP *, void *)
00088                             =first_timer->handler;
00089                      void *arg=first_timer->voidarg;
00090 
00091                      pcpdtimer_triggered(first_timer);
00092                      (*func)(pcp, arg);
00093               }
00094 
00095               if (termsig)
00096                      return (EOF);
00097                      
00098               if (first_timer)
00099               {
00100                      tvptr= &tv;
00101                      tv.tv_sec=first_timer->alarm-new_time;
00102                      tv.tv_usec=0;
00103               }
00104               else
00105                      tvptr=NULL;
00106 
00107               /*
00108               ** Read more input.  piggy-back after the
00109               ** input buffer :-)
00110               */
00111 
00112               if (input_line_len + BUFSIZ >= input_buffer_len)
00113               {
00114                      size_t n=input_line_len + BUFSIZ;
00115                      char *p=realloc(input_buffer, n);
00116 
00117                      if (!p)
00118                      {
00119                             perror("realloc");
00120                             exit(1);
00121                      }
00122                      input_buffer=p;
00123                      input_buffer_len=n;
00124               }
00125 
00126               inp_ptr=input_buffer + input_line_len;
00127 
00128               FD_ZERO(&fds);
00129               FD_SET(0, &fds);
00130 
00131               if (fflush(stdout) || ferror(stdout))
00132               {
00133                      perror("write");
00134                      termsig=1;
00135                      return (EOF);
00136               }
00137 
00138               if (select(1, &fds, NULL, NULL, tvptr) < 0)
00139               {
00140                      if (termsig)
00141                             return (EOF);
00142 
00143                      if (errno != EINTR)
00144                      {
00145                             perror("select");
00146                             return (EOF);
00147                      }
00148                      inp_left=0;
00149                      continue;
00150               }
00151 
00152               if (!FD_ISSET(0, &fds))
00153                      continue;
00154 
00155               inp_left=read(0, inp_ptr, BUFSIZ);
00156 
00157               if (termsig || inp_left == 0)
00158               {
00159                      termsig=1;
00160                      return (EOF);
00161               }
00162 
00163               if (inp_left < 0)
00164               {
00165                      perror("read");
00166                      return (EOF);
00167               }
00168        }
00169 
00170        c= *inp_ptr++;
00171        --inp_left;
00172        return ((int)(unsigned char)c);
00173 }
00174 
00175 /* --------------------------------------------------------------- */
00176 
00177 struct PCP *open_calendar(const char *p)
00178 {
00179         struct PCP *pcp;
00180         struct passwd *pw=getpwuid(getuid());
00181         const char *cp;
00182 
00183         if (!pw)
00184         {
00185                 perror("getpwuid");
00186                 exit(1);
00187         }
00188 
00189        userid=strdup(pw->pw_name);
00190 
00191         if (p && *p)
00192        {
00193               if (chdir(p))
00194               {
00195                      perror(p);
00196                      exit(1);
00197               }
00198        }
00199         else if ((cp=getenv("PCPDIR")) != NULL && *cp)
00200         {
00201               if (chdir(cp))
00202               {
00203                      perror(cp);
00204                      exit(1);
00205               }
00206         }
00207 
00208        pcp=pcp_open_dir(".", userid);
00209 
00210        if (pcp && pcp_cleanup(pcp))
00211        {
00212               pcp_close(pcp);
00213               pcp=NULL;
00214        }
00215 
00216        if (!pcp)
00217        {
00218               perror("pcp_open_dir");
00219               exit(1);
00220        }
00221        return (pcp);
00222 }
00223 
00224 /* --------------------------------------------------------------- */
00225 
00226 static void error(int n)
00227 {
00228         const char *p;
00229 
00230        switch (n) {
00231        case PCP_ERR_EVENTNOTFOUND:
00232               printf("504 Event not found\n");
00233               return;
00234        case PCP_ERR_EVENTLOCKED:
00235               printf("506 This event is temporarily locked\n");
00236               return;
00237        }
00238 
00239        p=pcp_strerror(n);
00240 
00241        printf("500 %s\n", p ? p:strerror(errno));
00242 }
00243 
00244 /* --------------------------------------------------------------- */
00245 
00246 struct proxy_list {
00247        struct proxy_list *next;
00248        char *userid;
00249        char *old_event_id;
00250        struct PCP *proxy;
00251        struct PCP_new_eventid *newevent;
00252        int flags;
00253 
00254 #define PROXY_NEW 1
00255 #define PROXY_IGNORE 2
00256 
00257 } ;
00258 
00259 struct proxy_list *proxy_list=NULL;
00260 
00261 static void proxy_list_rset()
00262 {
00263        struct proxy_list *p;
00264 
00265        while ((p=proxy_list) != NULL)
00266        {
00267               proxy_list=p->next;
00268               if (p->newevent)
00269                      pcp_destroy_eventid(p->proxy, p->newevent);
00270               pcp_close(p->proxy);
00271               free(p->userid);
00272               if (p->old_event_id)
00273                      free(p->old_event_id);
00274               proxy_list=p->next;
00275               free(p);
00276        }
00277 }
00278 
00279 /* Compare two e-mail addresses */
00280 
00281 static int addrcmp(const char *a, const char *b)
00282 {
00283        char *aa=NULL;
00284        const char *h=auth_myhostname();
00285        int rc;
00286 
00287        if (!h)
00288               return (1);
00289 
00290        if (strchr(a, '@') == NULL)
00291        {
00292               aa=malloc(strlen(a)+strlen(h)+2);
00293 
00294               if (!aa)
00295               {
00296                      fprintf(stderr, "NOTICE: malloc: out of memory.\n");
00297                      return (1);
00298               }
00299               strcat(strcat(strcpy(aa, a), "@"), h);
00300               rc=addrcmp(aa, b);
00301               free(aa);
00302               return (rc);
00303        }
00304 
00305        if (strchr(b, '@') == NULL)
00306        {
00307               aa=malloc(strlen(b)+strlen(h)+2);
00308 
00309               if (!aa)
00310               {
00311                      fprintf(stderr, "NOTICE: malloc: out of memory.\n");
00312                      return (1);
00313               }
00314               strcat(strcat(strcpy(aa, b), "@"), h);
00315               rc=addrcmp(a, aa);
00316               free(aa);
00317               return (rc);
00318        }
00319 
00320        rc=strcasecmp(a, b);
00321        return (rc);
00322 }
00323 
00324 static struct proxy_list *proxy(const char *proxy_userid, char **errmsg)
00325 {
00326        struct proxy_list *p;
00327 
00328        if (errmsg)
00329               *errmsg=0;
00330 
00331        for (p=proxy_list; p; p=p->next)
00332        {
00333               if (addrcmp(proxy_userid, p->userid) == 0)
00334                      return (p);
00335        }
00336 
00337        p=malloc(sizeof(struct proxy_list));
00338        if (!p)
00339               return (NULL);
00340        memset(p, 0, sizeof(*p));
00341 
00342        if ((p->userid=strdup(proxy_userid)) == NULL)
00343        {
00344               free(p);
00345               return (NULL);
00346        }
00347 
00348        if ((p->proxy=pcp_find_proxy(proxy_userid, NULL, errmsg)) == NULL ||
00349            pcp_set_proxy(p->proxy, userid))
00350        {
00351               if (p->proxy)
00352                      pcp_close(p->proxy);
00353               free(p->userid);
00354               free(p);
00355               return (NULL);
00356        }
00357 
00358        p->next=proxy_list;
00359        proxy_list=p;
00360        return (p);
00361 }
00362 
00363 /* --------------------------------------------------------------- */
00364 
00365 static void rset(struct PCP *pcp)
00366 {
00367        pcpdtimer_triggered(&rebook_timeout);
00368        if (new_eventid)
00369               pcp_destroy_eventid(pcp, new_eventid);
00370        if (new_commit_times)
00371               free(new_commit_times);
00372        new_commit_times=NULL;
00373        if (new_commit_participants)
00374               free(new_commit_participants);
00375        if (new_commit_participants_buf)
00376               free(new_commit_participants_buf);
00377        new_commit_participants=NULL;
00378        new_commit_participants_buf=NULL;
00379        new_commit.event_times=NULL;
00380        new_commit.n_event_times=0;
00381        new_eventid=NULL;
00382        if (deleted_eventid)
00383               free(deleted_eventid);
00384        deleted_eventid=NULL;
00385        notbooked=0;
00386        proxy_list_rset();
00387 }
00388 
00389 struct readnewevent_s {
00390        FILE *tmpfile;
00391        int seeneol;
00392        int seendot;
00393        int seeneof;
00394        int sentprompt;
00395        time_t last_noop_time;
00396 
00397        int cnt;
00398        struct PCP *pcp;
00399        struct pcpdtimer inactivity_timeout;
00400 } ;
00401 
00402 static int readnewevent_callback(char *p, int n, void *vp)
00403 {
00404        struct readnewevent_s *rne=(struct readnewevent_s *)vp;
00405        int cnt=0;
00406 
00407        if (!rne->sentprompt)
00408        {
00409               rne->sentprompt=1;
00410               printf("300 Send event text, terminate by a line with a single dot.\n");
00411        }
00412 
00413        while (!rne->seeneof && n)
00414        {
00415               int c=inputchar(rne->pcp);
00416 
00417               if (c == EOF)
00418               {
00419                      rne->seeneof=1;
00420                      errno=ETIMEDOUT;
00421                      return (-1);
00422               }
00423 
00424               if (c == '\r')
00425                      continue;
00426 
00427               if (c == '\n')
00428               {
00429                      if (rne->seendot)
00430                             rne->seeneof=1;
00431                      rne->seendot=0;
00432                      rne->seeneol=1;
00433                      if (rne->seeneof)
00434                             continue;
00435               }
00436               else
00437               {
00438                      rne->seendot= c == '.' && rne->seeneol;
00439                      rne->seeneol=0;
00440                      if (rne->seendot)
00441                             continue;
00442               }
00443               putc(c, rne->tmpfile);
00444               ++cnt;
00445               *p++ = c;
00446               --n;
00447 
00448               if (++rne->cnt >= 8192)
00449               {
00450                      time_t t;
00451 
00452                      time(&t);
00453                      if (t >= rne->last_noop_time+300) /* Don't timeout */
00454                      {
00455                             struct proxy_list *p;
00456                             rne->last_noop_time=t;
00457                             for (p=proxy_list; p; p=p->next)
00458                                    pcp_noop(p->proxy);
00459                      }
00460 
00461                      pcpdtimer_install(&rne->inactivity_timeout, 300);
00462                      rne->cnt=0;
00463               }
00464        }
00465        return (cnt);
00466 }
00467 
00468 static void proxy_error(const char *n, const char *msg)
00469 {
00470        while (*msg)
00471        {
00472               printf("500-%s - ", n);
00473               while (*msg)
00474               {
00475                      if (*msg == '\n')
00476                      {
00477                             ++msg;
00478                             break;
00479                      }
00480                      if (*msg != '\r')
00481                             putchar( *msg);
00482                      ++msg;
00483               }
00484               printf("\n");
00485        }
00486 
00487 }
00488 
00489 static int mkparticipants(struct PCP_save_event *se)
00490 {
00491        struct proxy_list *p;
00492        unsigned cnt;
00493        size_t l=0;
00494 
00495        if (new_commit_participants)
00496               free(new_commit_participants);
00497        if (new_commit_participants_buf)
00498               free(new_commit_participants_buf);
00499        new_commit_participants=NULL;
00500        new_commit_participants_buf=NULL;
00501 
00502        se->event_participants=NULL;
00503        se->n_event_participants=0;
00504 
00505        for (cnt=0, p=proxy_list; p; p=p->next)
00506        {
00507               if (!p->newevent)
00508                      continue;
00509 
00510               if (p->flags & PROXY_IGNORE)
00511                      continue;
00512 
00513               ++cnt;
00514               l += strlen(p->userid)+1;
00515 
00516               if (p->newevent->eventid)
00517                      l += strlen(p->newevent->eventid)+1;
00518        }
00519        if (cnt == 0)
00520               return (0);
00521 
00522        if ((new_commit_participants_buf=malloc(l)) == NULL)
00523               return (-1);
00524        if ((new_commit_participants
00525             =calloc(cnt, sizeof(struct PCP_event_participant))) == NULL)
00526               return (-1);
00527 
00528        l=0;
00529 
00530        for (cnt=0, p=proxy_list; p; p=p->next)
00531        {
00532               if (!p->newevent)
00533                      continue;
00534 
00535               if (p->flags & PROXY_IGNORE)
00536                      continue;
00537 
00538               new_commit_participants[cnt].address=
00539                      strcpy(new_commit_participants_buf+l, p->userid);
00540               l += strlen(p->userid)+1;
00541 
00542               if (p->newevent->eventid)
00543               {
00544                      new_commit_participants[cnt].eventid=
00545                             strcpy(new_commit_participants_buf+l,
00546                                    p->newevent->eventid);
00547                      l += strlen(p->newevent->eventid)+1;
00548               }
00549               ++cnt;
00550        }
00551        se->event_participants=new_commit_participants;
00552        se->n_event_participants=cnt;
00553        return (0);
00554 }
00555 
00556 static struct PCP_new_eventid *readnewevent(struct PCP *pcp)
00557 {
00558        struct PCP_save_event se;
00559        struct readnewevent_s rne;
00560        struct PCP_new_eventid *ne;
00561        const char *cp;
00562        struct proxy_list *p;
00563        int first_save=1;
00564 
00565        memset(&rne, 0, sizeof(rne));
00566        if (!deleted_eventid)
00567               proxy_list_rset();
00568 
00569        /* Open new proxy connections */
00570 
00571        while ((cp=strtok(NULL, " ")) != NULL)
00572        {
00573               char *errmsg, *q;
00574               char *n=strdup(cp);
00575               struct proxy_list *pcp;
00576 
00577               if (!n)
00578               {
00579                      fprintf(stderr, "ALERT: Out of memory.\n");
00580                      exit(1);
00581               }
00582 
00583               if (proxy_userid)
00584               {
00585                      printf("500-Cannot create proxy in proxy mode.\n");
00586                      free(n);
00587                      errno=EIO;
00588                      return (NULL);
00589               }
00590 
00591               strcpy(n, cp);
00592               pcp=proxy(n, &errmsg);
00593 
00594               if (pcp)
00595               {
00596                      pcp->flags |= PROXY_NEW;
00597                      free(n);
00598                      continue;
00599               }
00600 
00601               if (force_flag)
00602               {
00603                      pcp->flags |= PROXY_IGNORE;
00604                      free(n);
00605                      continue;
00606               }
00607 
00608               while (errmsg && (q=strchr(errmsg, '\n')) != 0)
00609                      *q='/';
00610               printf("500-%s: %s\n", n, errmsg ? errmsg:"Failed to create a proxy connection.");
00611               free(n);
00612               proxy_list_rset();
00613               return (NULL);
00614        }
00615 
00616        memset(&se, 0, sizeof(se));
00617        if ((rne.tmpfile=tmpfile()) == NULL)
00618               return (NULL);
00619        time(&rne.last_noop_time);
00620 
00621        rne.seeneol=1;
00622        rne.seendot=0;
00623        rne.seeneof=0;
00624        rne.cnt=0;
00625        rne.pcp=pcp;
00626        pcpdtimer_init(&rne.inactivity_timeout);
00627        rne.inactivity_timeout.handler=&inactive;
00628        pcpdtimer_install(&rne.inactivity_timeout, 300);
00629 
00630        for (p=proxy_list; p; p=p->next)
00631        {
00632               struct PCP_save_event se;
00633 
00634               if ( !(p->flags & PROXY_NEW))
00635                      continue;
00636 
00637               if (fseek(rne.tmpfile, 0L, SEEK_SET) < 0
00638                   || lseek(fileno(rne.tmpfile), 0L, SEEK_SET) < 0)
00639               {
00640                      int save_errno=errno;
00641                      proxy_list_rset();
00642                      pcpdtimer_triggered(&rne.inactivity_timeout);
00643                      fclose(rne.tmpfile);
00644                      errno=save_errno;
00645                      return (NULL);
00646               }
00647 
00648               memset(&se, 0, sizeof(se));
00649               if (first_save)
00650               {
00651                      se.write_event_func_misc_ptr= &rne;
00652                      se.write_event_func=readnewevent_callback;
00653               }
00654               else
00655                      se.write_event_fd=fileno(rne.tmpfile);
00656 
00657               if ((p->newevent=pcp_new_eventid(p->proxy,
00658                                            p->old_event_id,
00659                                            &se)) == NULL)
00660               {
00661                      pcpdtimer_triggered(&rne.inactivity_timeout);
00662 
00663                      if (force_flag)
00664                      {
00665                             /* Force it through */
00666 
00667                             p->flags &= ~PROXY_NEW;
00668                             p->flags |= PROXY_IGNORE;
00669                             continue;
00670                      }
00671 
00672                      proxy_error(p->userid,
00673                                 pcp_errmsg(p->proxy));
00674                      proxy_list_rset();
00675                      fclose(rne.tmpfile);
00676                      errno=EIO;
00677                      return (NULL);
00678               }
00679               if (first_save)
00680                      pcpdtimer_triggered(&rne.inactivity_timeout);
00681               first_save=0;
00682        }
00683 
00684 
00685        if (first_save)
00686        {
00687               se.write_event_func_misc_ptr= &rne;
00688               se.write_event_func=readnewevent_callback;
00689        }
00690        else
00691               se.write_event_fd=fileno(rne.tmpfile);
00692 
00693        if (mkparticipants(&se) || fseek(rne.tmpfile, 0L, SEEK_SET) < 0
00694            || lseek(fileno(rne.tmpfile), 0L, SEEK_SET) < 0)
00695        {
00696               int save_errno=errno;
00697 
00698               proxy_list_rset();
00699               fclose(rne.tmpfile);
00700               errno=save_errno;
00701               return (NULL);
00702        }
00703 
00704        if ((ne=pcp_new_eventid(pcp, deleted_eventid, &se)) == NULL)
00705        {
00706               while (!rne.seeneof)
00707               {
00708                      char buf[512];
00709 
00710                      readnewevent_callback(buf, sizeof(buf), &se);
00711               }
00712        }
00713        pcpdtimer_triggered(&rne.inactivity_timeout);
00714        if (first_save)
00715        {
00716               if (fflush(rne.tmpfile) || ferror(rne.tmpfile))
00717               {
00718                      int save_errno=errno;
00719 
00720                      proxy_list_rset();
00721                      fclose(rne.tmpfile);
00722                      errno=save_errno;
00723                      return (NULL);
00724               }
00725        }
00726 
00727        notbooked=1;
00728        fclose(rne.tmpfile);
00729        return (ne);
00730 }
00731 
00732 struct book_time_list {
00733        struct book_time_list *next;
00734        struct PCP_event_time times;
00735 } ;
00736 
00737 struct report_conflict_info {
00738        struct report_conflict_info *next;
00739        char *conflict_eventid;
00740        char *conflict_addr;
00741        time_t conflict_start;
00742        time_t conflict_end;
00743 } ;
00744 
00745 struct extra_conflict_info {
00746        struct report_conflict_info **conflict_list;
00747        const char *proxy_addr;
00748 } ;
00749 
00750 static int do_report_conflict(const char *e, time_t start, time_t end,
00751                         const char *addr, void *vp)
00752 {
00753        struct extra_conflict_info *eci=(struct extra_conflict_info *)vp;
00754        struct report_conflict_info **p=eci->conflict_list;
00755        struct report_conflict_info *q=malloc(sizeof(**p));
00756 
00757        if (!q)
00758               return (-1);
00759 
00760        if (eci->proxy_addr)
00761               addr=eci->proxy_addr;
00762 
00763        if ((q->conflict_eventid=strdup(e)) == NULL)
00764        {
00765               free(q);
00766               return (-1);
00767        }
00768 
00769        if ((q->conflict_addr=strdup(addr)) == NULL)
00770        {
00771               free(q->conflict_eventid);
00772               free(q);
00773               return (-1);
00774        }
00775 
00776        while (*p)
00777        {
00778               p= &(*p)->next;
00779        }
00780 
00781        *p=q;
00782        q->next=0;
00783        q->conflict_start=start;
00784        q->conflict_end=end;
00785        return (0);
00786 }
00787 
00788 static void report_conflict_destroy(struct report_conflict_info *p)
00789 {
00790        struct report_conflict_info *q;
00791 
00792        while ((q=p) != 0)
00793        {
00794               p=q->next;
00795               free(q->conflict_addr);
00796               free(q->conflict_eventid);
00797               free(q);
00798        }
00799 }
00800 
00801 static void rebook(struct PCP *, void *);
00802 
00803 static void rebook_installtimeout(struct PCP *pcp)
00804 {
00805        rebook_timeout.handler=rebook;
00806        pcpdtimer_install(&rebook_timeout, 15 * 60);
00807 }
00808 
00809 static void rebook(struct PCP *pcp, void *vp)
00810 {
00811        struct proxy_list *p;
00812 
00813        pcp_noop(pcp);
00814 
00815        for (p=proxy_list; p; p=p->next)
00816               pcp_noop(p->proxy);
00817        rebook_installtimeout(pcp);
00818 }
00819 
00820 static void dobook(struct PCP *pcp)
00821 {
00822        struct book_time_list *list, **last;
00823        unsigned n=0;
00824        const char *p;
00825        int rc=0;
00826        struct PCP_event_time *new_times=NULL;
00827        struct report_conflict_info *conflict_list;
00828 
00829        list=NULL;
00830        last= &list;
00831 
00832        while ((p=strtok(NULL, " ")) != NULL)
00833        {
00834               char from_s[14+1];
00835               char to_s[14+1];
00836 
00837               if (strlen(p) != 14 + 14 + 1 || p[14] != '-')
00838               {
00839                      printf("500 Syntax error.\n");
00840                      rc= -1;
00841                      break;
00842               }
00843 
00844               memcpy(from_s, p, 14);
00845               memcpy(to_s, p+15, 14);
00846               from_s[14]=0;
00847               to_s[14]=0;
00848 
00849               if ( (*last=malloc(sizeof(**last))) == NULL)
00850               {
00851                      printf("500 %s\n", strerror(errno));
00852                      rc= -1;
00853                      break;
00854               }
00855 
00856               (*last)->next=NULL;
00857               if (((*last)->times.start=pcp_gmtime_s(from_s)) == 0 ||
00858                   ((*last)->times.end=pcp_gmtime_s(to_s)) == 0)
00859               {
00860                      printf("500 Invalid date/time\n");
00861                      rc= -1;
00862                      break;
00863               }
00864 
00865               last=&(*last)->next;
00866               ++n;
00867        }
00868 
00869        if (rc == 0 && n == 0)
00870        {
00871               printf("500 Syntax error\n");
00872               rc= -1;
00873        }
00874 
00875        if (rc == 0 && (new_times=calloc(n, sizeof(struct PCP_event_time)))
00876            == NULL)
00877        {
00878               printf("500 %s\n", strerror(errno));
00879               rc= -1;
00880        }
00881 
00882        if (rc == 0)
00883        {
00884               struct book_time_list *l;
00885               const struct PCP_event_time *save_times;
00886               unsigned n_save_times;
00887               struct proxy_list *pr;
00888               int is_conflict;
00889               struct extra_conflict_info eci;
00890 
00891               n=0;
00892               for (l=list; l; l=l->next)
00893                      new_times[n++]= l->times;
00894 
00895               save_times=new_commit.event_times;
00896               n_save_times=new_commit.n_event_times;
00897 
00898               new_commit.event_times=new_times;
00899               new_commit.n_event_times=n;
00900 
00901               eci.conflict_list= &conflict_list;
00902 
00903               conflict_list=NULL;
00904               new_commit.add_conflict_callback=do_report_conflict;
00905               new_commit.add_conflict_callback_ptr= &eci;
00906               new_commit.flags=
00907                      (conflict_flag ? PCP_OK_CONFLICT:0) |
00908                      (force_flag ? PCP_OK_PROXY_ERRORS:0);
00909 
00910               notbooked=1;
00911               is_conflict=0;
00912 
00913               for (pr=proxy_list; pr; pr=pr->next)
00914               {
00915                      eci.proxy_addr=pr->userid;
00916 
00917                      if (pr->flags & PROXY_NEW)
00918                             if (pcp_book(pr->proxy,
00919                                         pr->newevent, &new_commit))
00920                                    is_conflict=1;
00921               }
00922 
00923               if (proxy_userid)
00924                      new_commit.flags |= PCP_BYPROXY;
00925 
00926               eci.proxy_addr=NULL;
00927               if (pcp_book(pcp, new_eventid, &new_commit))
00928                      is_conflict=1;
00929 
00930               if (is_conflict)
00931               {
00932                      new_commit.event_times=save_times;
00933                      new_commit.n_event_times=n_save_times;
00934                      free(new_times);
00935 
00936                      if (conflict_list)
00937                      {
00938                             struct report_conflict_info *p;
00939 
00940                             for (p=conflict_list; p; p=p->next)
00941                             {
00942                                    char from_buf[15];
00943                                    char to_buf[15];
00944 
00945                                    pcp_gmtimestr(p->conflict_start,
00946                                                 from_buf);
00947                                    pcp_gmtimestr(p->conflict_end, to_buf);
00948 
00949                                    printf("403%c%s %s %s %s conflicts.\n",
00950                                           p->next ? '-':' ',
00951                                           p->conflict_addr,
00952                                           from_buf,
00953                                           to_buf,
00954                                           p->conflict_eventid);
00955                             }
00956                      }
00957                      else
00958                      {
00959                             error(new_commit.errcode);
00960                      }
00961                      report_conflict_destroy(conflict_list);
00962               }
00963               else
00964               {
00965                      if (new_commit_times)
00966                             free(new_commit_times);
00967                      new_commit_times=new_times;
00968                      printf("200 Ok\n");
00969                      notbooked=0;
00970               }
00971               rebook_installtimeout(pcp);
00972        }
00973 
00974        while (list)
00975        {
00976               struct book_time_list *l=list;
00977 
00978               list=l->next;
00979               free(l);
00980        }
00981 
00982 }
00983 
00984 /* ------- LIST ------- */
00985 
00986 struct list_struct {
00987        struct PCP_list_all list_info;
00988        struct list_item *event_list, **last_event;
00989 } ;
00990 
00991 struct list_item {
00992        struct list_item *next;
00993        char *event_id;
00994        time_t start;
00995        time_t end;
00996 } ;
00997 
00998 static int list_callback(struct PCP_list_all *p, void *vp)
00999 {
01000        struct list_struct *ls=(struct list_struct *)vp;
01001        char *s=strdup(p->event_id);
01002 
01003        if (!s)
01004               return (-1);
01005 
01006        if ( ((*ls->last_event)=(struct list_item *)
01007              malloc(sizeof(struct list_item))) == NULL)
01008        {
01009               free(s);
01010               return (-1);
01011        }
01012 
01013        (*ls->last_event)->event_id=s;
01014        (*ls->last_event)->start=p->event_from;
01015        (*ls->last_event)->end=p->event_to;
01016        (*ls->last_event)->next=NULL;
01017 
01018        ls->last_event= & (*ls->last_event)->next;
01019        return (0);
01020 }
01021        
01022 static int list(struct PCP *pcp)
01023 {
01024        struct list_struct ls;
01025        const char *q;
01026        struct list_item *e;
01027 
01028        memset(&ls, 0, sizeof(ls));
01029        ls.list_info.callback_arg= &ls;
01030        ls.list_info.callback_func= &list_callback;
01031        ls.last_event= &ls.event_list;
01032 
01033        while ((q=strtok(NULL, " ")) != NULL)
01034        {
01035               if (strcasecmp(q, "FROM") == 0)
01036               {
01037                      char buf[15];
01038 
01039                      q=strtok(NULL, " ");
01040                      if (!q)
01041                             return (-1);
01042                      if (ls.list_info.list_from ||
01043                          ls.list_info.list_to)
01044                             return (-1);
01045 
01046                      if (*q != '-')
01047                      {
01048                             if (strlen(q) < 14)
01049                                    return (-1);
01050                             memcpy(buf, q, 14);
01051                             buf[14]=0;
01052                             q += 14;
01053                             if ((ls.list_info.list_from
01054                                  =pcp_gmtime_s(buf)) == 0)
01055                                    return (-1);
01056                      }
01057                      if (*q)
01058                      {
01059                             if (*q++ != '-' || strlen(q) != 14)
01060                                    return (-1);
01061                             memcpy(buf, q, 14);
01062                             buf[14]=0;
01063                             q += 14;
01064                             if ((ls.list_info.list_to
01065                                  =pcp_gmtime_s(buf)) == 0)
01066                                    return (-1);
01067                      }
01068               }
01069        }
01070 
01071        if (pcp_list_all(pcp, &ls.list_info))
01072        {
01073               error(0);
01074        }
01075        else
01076        {
01077               for (e=ls.event_list; e; e=e->next)
01078               {
01079                      char from_buf[15], to_buf[15];
01080 
01081                      pcp_gmtimestr(e->start, from_buf);
01082                      pcp_gmtimestr(e->end, to_buf);
01083 
01084                      printf("105%c%s %s %s event found.\n",
01085                             e->next ? '-':' ',
01086                             e->event_id,
01087                             from_buf,
01088                             to_buf);
01089               }
01090 
01091               if (ls.event_list == NULL)
01092                      printf("504 event-id not found.\n");
01093        }
01094 
01095        while ((e=ls.event_list) != NULL)
01096        {
01097               ls.event_list=e->next;
01098               free(e->event_id);
01099               free(e);
01100        }
01101        return (0);
01102 }
01103 
01104 /* ------ RETR ------------ */
01105 
01106 struct retrinfo {
01107        int status;
01108        struct retrinfo_event_list *event_list;
01109        const char **event_list_array;
01110        int text_flag;
01111        int text_seen_eol;
01112 } ;
01113 
01114 struct retrinfo_event_list {
01115        struct retrinfo_event_list *next;
01116        char *event_id;
01117 } ;
01118 
01119 static int callback_retr_date(struct PCP_retr *r,
01120                            time_t from, time_t to, void *vp)
01121 {
01122        char from_buf[15], to_buf[15];
01123 
01124        pcp_gmtimestr(from, from_buf);
01125        pcp_gmtimestr(to, to_buf);
01126 
01127        printf("105 %s %s %s event found\n",
01128               r->event_id, from_buf, to_buf);
01129        return (0);
01130 }
01131 
01132 static int callback_retr_participants(struct PCP_retr *r,
01133                                   const char *n, const char *id,
01134                                   void *vp)
01135 {
01136        printf("106 %s %s is a participant\n", r->event_id, n);
01137        return (0);
01138 }
01139 
01140 static int callback_retr_status(struct PCP_retr *r,
01141                             int status, void *vp)
01142 {
01143        char status_buf[256];
01144        const char *comma="";
01145 
01146        status_buf[0]=0;
01147 
01148        if (status & LIST_CANCELLED)
01149        {
01150               strcat(strcat(status_buf, comma), "CANCELLED");
01151               comma=",";
01152        }
01153 
01154        if (status & LIST_BOOKED)
01155        {
01156               strcat(strcat(status_buf, comma), "BOOKED");
01157               comma=",";
01158        }
01159 
01160        if (status & LIST_PROXY)
01161        {
01162               strcat(strcat(status_buf, comma), "PROXY");
01163               comma=",";
01164        }
01165        if (status_buf[0])
01166               printf("110 %s %s\n", r->event_id, status_buf);
01167        return (0);
01168 }
01169 
01170 static int callback_retr_begin(struct PCP_retr *r, void *vp)
01171 {
01172        struct retrinfo *ri=(struct retrinfo *)vp;
01173 
01174        ri->text_flag=0;
01175        ri->text_seen_eol=1;
01176 
01177        return (0);
01178 }
01179 
01180 static int callback_retr_headers(struct PCP_retr *r,
01181                              const char *h,
01182                              const char *v,
01183                              void *vp)
01184 {
01185        struct retrinfo *ri=(struct retrinfo *)vp;
01186        int lastchar;
01187 
01188        if (!ri->text_flag)
01189        {
01190               ri->text_flag=1;
01191               printf("107 %s follows\n", r->event_id);
01192        }
01193 
01194        if (*h == '.')
01195               putchar('.');
01196        printf("%s: ", h);
01197 
01198        while (*v && isspace((int)(unsigned char)*v))
01199               ++v;
01200 
01201        lastchar=' ';
01202 
01203        while (*v)
01204        {
01205               if ((int)(unsigned char)*v >= ' ' ||
01206                   *v == '\n' || *v == '\t')
01207               {
01208                      putchar(*v);
01209                      lastchar=*v;
01210               }
01211               ++v;
01212        }
01213        if (lastchar != '\n')
01214               putchar('\n');
01215        return (0);
01216 }
01217 
01218 static int callback_retr_message(struct PCP_retr *r,
01219                              const char *ptr,
01220                              int l,
01221                              void *vp)
01222 {
01223        struct retrinfo *ri=(struct retrinfo *)vp;
01224 
01225        if (!ri->text_flag)
01226        {
01227               ri->text_flag=1;
01228               printf("107 %s follows\n", r->event_id);
01229        }
01230 
01231        while (l)
01232        {
01233               if (ri->text_seen_eol && *ptr == '.')
01234                      putchar('.');
01235               ri->text_seen_eol= *ptr == '\n';
01236               putchar(*ptr);
01237               ++ptr;
01238               --l;
01239        }
01240        return (0);
01241 }
01242 
01243 static int callback_retr_end(struct PCP_retr *r, void *vp)
01244 {
01245        struct retrinfo *ri=(struct retrinfo *)vp;
01246 
01247        if (ri->text_flag)
01248        {
01249               if (!ri->text_seen_eol)
01250                      putchar('\n');
01251               printf(".\n");
01252        }
01253        return (0);
01254 }
01255 
01256 static int retr(struct PCP *pcp)
01257 {
01258        struct PCP_retr r;
01259        struct retrinfo ri;
01260        const char *q;
01261        int n;
01262        struct retrinfo_event_list *p;
01263 
01264        memset(&r, 0, sizeof(r));
01265        memset(&ri, 0, sizeof(ri));
01266 
01267        r.callback_arg= &ri;
01268 
01269        for (;;)
01270        {
01271               if ((q=strtok(NULL, " ")) == NULL)
01272                      return (-1);
01273 
01274               if (strcasecmp(q, "EVENTS") == 0)
01275                      break;
01276 
01277               if (strcasecmp(q, "TEXT") == 0)
01278               {
01279                      r.callback_begin_func=callback_retr_begin;
01280                      r.callback_rfc822_func=callback_retr_message;
01281                      r.callback_end_func=callback_retr_end;
01282                      continue;
01283               }
01284 
01285               if (strcasecmp(q, "HEADERS") == 0)
01286               {
01287                      r.callback_begin_func=callback_retr_begin;
01288                      r.callback_headers_func=callback_retr_headers;
01289                      r.callback_end_func=callback_retr_end;
01290                      continue;
01291               }
01292 
01293               if (strcasecmp(q, "DATE") == 0)
01294               {
01295                      r.callback_retr_date=callback_retr_date;
01296                      continue;
01297               }
01298 
01299               if (strcasecmp(q, "ADDR") == 0)
01300               {
01301                      r.callback_retr_participants=
01302                             callback_retr_participants;
01303                      continue;
01304               }
01305 
01306               if (strcasecmp(q, "STATUS") == 0)
01307               {
01308                      r.callback_retr_status=callback_retr_status;
01309                      continue;
01310               }
01311               return (-1);
01312        }
01313 
01314        if (r.callback_headers_func && r.callback_rfc822_func)
01315               return (-1);
01316 
01317        n=0;
01318        while ((q=strtok(NULL, " ")) != NULL)
01319        {
01320               char *s=strdup(q);
01321 
01322               if (!s || (p=malloc(sizeof(struct retrinfo_event_list)))
01323                   == NULL)
01324               {
01325                      perror("malloc");
01326                      exit(1);
01327               }
01328               p->event_id=s;
01329               p->next=ri.event_list;
01330               ri.event_list=p;
01331               ++n;
01332        }
01333 
01334        if (ri.event_list == NULL)
01335               return (-1);
01336 
01337        if ((ri.event_list_array=malloc((n+1) * sizeof(const char *)))
01338            == NULL)
01339        {
01340               perror("malloc");
01341               exit(1);
01342        }
01343 
01344        n=0;
01345        for (p=ri.event_list; p; p=p->next)
01346               ri.event_list_array[n++]=p->event_id;
01347        ri.event_list_array[n]=0;
01348 
01349        r.event_id_list=ri.event_list_array;
01350 
01351        if (pcp_retr(pcp, &r))
01352               error(r.errcode);
01353        else
01354               printf("108 RETR complete\n");
01355 
01356        while ((p=ri.event_list) != 0)
01357        {
01358               ri.event_list=p->next;
01359               free(p->event_id);
01360               free(p);
01361        }
01362        free(ri.event_list_array);
01363        return (0);
01364 }
01365 
01366 /* ---- UNCANCEL ---- */
01367 
01368 struct uncancel_list {
01369        struct uncancel_list *next;
01370        char *id;
01371        time_t from, to;
01372        char *addr;
01373 } ;
01374 
01375 static int uncancel_callback(const char *event, time_t from, time_t to,
01376                           const char *addr, void *vp)
01377 {
01378        struct uncancel_list ***tail_ptr=(struct uncancel_list ***)vp;
01379        struct uncancel_list **tail= *tail_ptr;
01380        char *s=strdup(event);
01381        char *a=strdup(addr);
01382        struct uncancel_list *newptr;
01383 
01384        if (!s || !a || (newptr=(struct uncancel_list *)
01385                       malloc(sizeof(struct uncancel_list))) == NULL)
01386        {
01387               if (a) free(a);
01388               if (s) free(s);
01389               return (-1);
01390        }
01391 
01392        newptr->addr=a;
01393        newptr->id=s;
01394        newptr->from=from;
01395        newptr->to=to;
01396 
01397        *tail=newptr;
01398        newptr->next=0;
01399 
01400        *tail_ptr= &(*tail)->next;
01401        return (0);
01402 }
01403 
01404 /* --------- ACL LIST ---------- */
01405 
01406 struct acl_list {
01407        struct acl_list *next;
01408        char *who;
01409        int flags;
01410 } ;
01411 
01412 static int list_acl_callback(const char *who, int flags, void *dummy)
01413 {
01414        struct acl_list **p=(struct acl_list **)dummy;
01415        struct acl_list *q=malloc(sizeof(struct acl_list));
01416 
01417        if (!q)
01418               return (-1);
01419        if ((q->who=strdup(who)) == NULL)
01420        {
01421               free(q);
01422               return (-1);
01423        }
01424        q->flags=flags;
01425        q->next= *p;
01426        *p=q;
01427        return (0);
01428 }
01429 
01430 static void listacls(struct PCP *pcp)
01431 {
01432        char buf[1024];
01433        struct acl_list *list=NULL;
01434        struct acl_list *p;
01435 
01436        if (pcp_list_acl(pcp, list_acl_callback, &list) == 0)
01437        {
01438               if (list == NULL)
01439                      printf("203 Empty ACL\n");
01440               else
01441               {
01442                      for (p=list; p; p=p->next)
01443                      {
01444                             buf[0]=0;
01445                             pcp_acl_name(p->flags, buf);
01446                             printf("103%c%s %s\n",
01447                                    p->next ? '-':' ',
01448                                    p->who, buf);
01449                      }
01450               }
01451        }
01452        else error(0);
01453 
01454        while ((p=list) != NULL)
01455        {
01456               list=p->next;
01457               free(p->who);
01458               free(p);
01459        }
01460 }
01461 
01462 static int open_event_participant(struct PCP_retr *r,
01463                               const char *n, const char *id,
01464                               void *vp)
01465 {
01466        struct proxy_list *p;
01467        char *errmsg;
01468 
01469        if (proxy_userid)
01470        {
01471               printf("500-Cannot create proxy in proxy mode.\n");
01472               errno=EIO;
01473               return (-1);
01474        }
01475 
01476        p=proxy(n, &errmsg);
01477 
01478        if (p)
01479        {
01480               if ((p->old_event_id=strdup(id)) == NULL)
01481                      return (-1);
01482               return (0);
01483        }
01484 
01485        if (!force_flag)
01486        {
01487               if (errmsg)
01488               {
01489                      proxy_error(n, errmsg);
01490                      free(errmsg);
01491               }
01492               errno=EIO;
01493               return (-1);
01494        }
01495        if (errmsg)
01496               free(errmsg);
01497 
01498        p->flags |= PROXY_IGNORE;
01499        return (0);
01500 }
01501 
01502 /* ------------------------ */
01503 
01504 static int check_acl(int, int);
01505 
01506 static int doline(struct PCP *pcp, char *p, int acl_flags)
01507 {
01508        char *q=strtok(p, " ");
01509 
01510        if (!q)
01511        {
01512               printf("500 Syntax error\n");
01513               return (0);
01514        }
01515 
01516        if (strcasecmp(q, "QUIT") == 0)
01517        {
01518               printf("200 Bye.\n");
01519               return (-1);
01520        }
01521 
01522        if (strcasecmp(q, "NOOP") == 0)
01523        {
01524               printf("200 Ok.\n");
01525               return (0);
01526        }
01527 
01528        if (strcasecmp(q, "CAPABILITY") == 0)
01529        {
01530               printf("100-ACL\n");
01531               printf("100 PCP1\n");
01532               return (0);
01533        }
01534 
01535        if (strcasecmp(q, "LIST") == 0)
01536        {
01537               if (check_acl(acl_flags, PCP_ACL_LIST))
01538                      return (0);
01539 
01540               if (list(pcp))
01541                      printf("500 Syntax error\n");
01542               return (0);
01543        }
01544 
01545        if (strcasecmp(q, "RETR") == 0)
01546        {
01547               if (check_acl(acl_flags, PCP_ACL_RETR))
01548                      return (0);
01549 
01550               if (retr(pcp))
01551                      printf("500 Syntax error\n");
01552               return (0);
01553        }
01554 
01555 
01556        if (strcasecmp(q, "ACL") == 0 && pcp_has_acl(pcp) && !proxy_userid)
01557        {
01558               q=strtok(NULL, " ");
01559               if (q && strcasecmp(q, "SET") == 0)
01560               {
01561                      const char *who=strtok(NULL, " ");
01562 
01563                      if (who)
01564                      {
01565                             int flags=0;
01566 
01567                             while ((q=strtok(NULL, " ")) != 0)
01568                                    flags |= pcp_acl_num(q);
01569 
01570                             if (pcp_acl(pcp, who, flags))
01571                             {
01572                                    error(0);
01573                                    return (0);
01574                             }
01575                             printf("200 Ok\n");
01576                             return (0);
01577                      }
01578               }
01579               else if (q && strcasecmp(q, "LIST") == 0)
01580               {
01581                      listacls(pcp);
01582                      return (0);
01583               }
01584        }
01585 
01586        if (strcasecmp(q, "RSET") == 0)
01587        {
01588               conflict_flag=0;
01589               force_flag=0;
01590               need_rset=0;
01591               rset(pcp);
01592               printf("200 Ok.\n"); 
01593               return (0);
01594        }
01595 
01596        if (need_rset)
01597        {
01598               printf("500 RSET required - calendar in an unknown state.\n");
01599               return (0);
01600        }
01601 
01602        if (strcasecmp(q, "DELETE") == 0)
01603        {
01604               struct PCP_retr r;
01605               const char *event_id_list[2];
01606 
01607               char *e=strtok(NULL, " ");
01608 
01609               if (check_acl(acl_flags, PCP_ACL_MODIFY))
01610                      return (0);
01611 
01612               if (e && deleted_eventid == NULL && new_eventid == NULL)
01613               {
01614                      if ((deleted_eventid=strdup(e)) == NULL)
01615                      {
01616                             perror("strdup");
01617                             exit(1);
01618                      }
01619                      proxy_list_rset();
01620                      memset(&r, 0, sizeof(r));
01621                      r.callback_retr_participants=open_event_participant;
01622                      event_id_list[0]=deleted_eventid;
01623                      event_id_list[1]=NULL;
01624                      r.event_id_list=event_id_list;
01625                      if (pcp_retr(pcp, &r))
01626                      {
01627                             error(r.errcode);
01628                             proxy_list_rset();
01629                      }
01630                      else
01631                             printf("200 Ok.\n");
01632                      return (0);
01633               }
01634        }
01635 
01636        if (strcasecmp(q, "NEW") == 0 && new_eventid == NULL)
01637        {
01638               if (check_acl(acl_flags, PCP_ACL_MODIFY))
01639                      return (0);
01640 
01641               new_eventid=readnewevent(pcp);
01642 
01643               if (new_eventid == NULL)
01644               {
01645                      printf("500 %s\n", strerror(errno));
01646               }
01647               else
01648                      printf("109 %s ready to be commited.\n",
01649                             new_eventid->eventid);
01650               return (0);
01651        }
01652 
01653        if (strcasecmp(q, "BOOK") == 0 && new_eventid)
01654        {
01655               dobook(pcp);
01656               return (0);
01657        }
01658 
01659        if (strcasecmp(q, "CONFLICT") == 0)
01660        {
01661               q=strtok(NULL, " ");
01662               if (q && strcasecmp(q, "ON") == 0)
01663               {
01664                      if (check_acl(acl_flags, PCP_ACL_CONFLICT))
01665                             return (0);
01666 
01667                      conflict_flag=1;
01668               }
01669               else
01670                      conflict_flag=0;
01671               printf("200 Ok.\n");
01672               return (0);
01673        }
01674 
01675        if (strcasecmp(q, "FORCE") == 0)
01676        {
01677               q=strtok(NULL, " ");
01678               if (q && strcasecmp(q, "ON") == 0)
01679               {
01680                      force_flag=1;
01681               }
01682               else
01683                      force_flag=0;
01684               printf("200 Ok.\n");
01685               return (0);
01686        }
01687 
01688        if (strcasecmp(q, "COMMIT") == 0)
01689        {
01690               if (notbooked)
01691               {
01692                      printf("500 BOOK required.\n");
01693               }
01694               else if (new_eventid && new_commit_times)
01695               {
01696                      struct proxy_list *pl;
01697 
01698                      new_commit.add_conflict_callback=NULL;
01699                      new_commit.add_conflict_callback_ptr=NULL;
01700 
01701                      new_commit.flags=
01702                             (conflict_flag ? PCP_OK_CONFLICT:0) |
01703                             (force_flag ? PCP_OK_PROXY_ERRORS:0);
01704 
01705                      for (pl=proxy_list; pl; pl=pl->next)
01706                      {
01707                             if (pl->flags & PROXY_IGNORE)
01708                                    continue;
01709 
01710                             if (pl->flags & PROXY_NEW)
01711                             {
01712                                    if (pcp_commit(pl->proxy,
01713                                                  pl->newevent,
01714                                                  &new_commit))
01715                                    {
01716                                           fprintf(stderr, "CRIT: "
01717                                                  "COMMIT failed for PROXY %s\n",
01718                                                  pl->userid);
01719 
01720                                           if (!force_flag)
01721                                           {
01722                                                  pl->flags &=
01723                                                         ~PROXY_NEW;
01724                                                  error(new_commit
01725                                                        .errcode);
01726                                                  return (0);
01727                                           }
01728                                    }
01729                             }
01730                             else if (pl->old_event_id)
01731                             {
01732                                    struct PCP_delete del;
01733 
01734                                    memset(&del, 0, sizeof(del));
01735 
01736                                    del.id=pl->old_event_id;
01737 
01738                                    if (pcp_delete(pl->proxy, &del))
01739                                    {
01740                                           fprintf(stderr, "CRIT: "
01741                                                  "DELETE failed for PROXY %s\n",
01742                                                  pl->userid);
01743                                           if (!force_flag)
01744                                           {
01745                                                  error(del.errcode);
01746                                                  return (0);
01747                                           }
01748                                           pl->flags |= PROXY_IGNORE;
01749                                    }
01750                             }
01751                      }
01752 
01753                      if (proxy_userid)
01754                             new_commit.flags |= PCP_BYPROXY;
01755 
01756                      if (pcp_commit(pcp, new_eventid, &new_commit))
01757                             error(new_commit.errcode);
01758                      else
01759                      {
01760                             const char *proxy_name=NULL;
01761                             const char *proxy_action=NULL;
01762 
01763                             for (pl=proxy_list; pl; pl=pl->next)
01764                             {
01765                                    if (proxy_name)
01766                                           printf("111-%s %s\n",
01767                                                  proxy_action,
01768                                                  proxy_name);
01769 
01770                                    proxy_action=
01771                                           !(pl->flags & PROXY_IGNORE)
01772                                           && (pl->flags & PROXY_NEW)
01773                                           ? "NEW":"DELETE";
01774                                    proxy_name=pl->userid;
01775                             }
01776 
01777                             if (proxy_name)
01778                                    printf("111 %s %s\n",
01779                                           proxy_action,
01780                                           proxy_name);
01781                             else
01782                                    printf("200 Ok.\n");
01783                      }      
01784                      rset(pcp);
01785                      return (0);
01786               }
01787               else if (!new_eventid && deleted_eventid)
01788               {
01789                      struct proxy_list *pl;
01790                      struct PCP_delete del;
01791                      const char *proxy_userid;
01792 
01793                      for (pl=proxy_list; pl; pl=pl->next)
01794                      {
01795                             if (pl->flags & PROXY_IGNORE)
01796                                    continue;
01797 
01798                             if (pl->old_event_id)
01799                             {
01800                                    memset(&del, 0, sizeof(del));
01801                                    del.id=pl->old_event_id;
01802 
01803                                    if (pcp_delete(pl->proxy, &del))
01804                                    {
01805                                           fprintf(stderr, "CRIT: "
01806                                                  "DELETE failed for PROXY %s\n",
01807                                                  pl->userid);
01808                                    }
01809                             }
01810                      }
01811 
01812                      memset(&del, 0, sizeof(del));
01813                      del.id=deleted_eventid;
01814 
01815                      if (pcp_delete(pcp, &del))
01816                      {
01817                             if (del.errcode != PCP_ERR_EVENTNOTFOUND)
01818                             {
01819                                    error(del.errcode);
01820                                    return (0);
01821                             }
01822                      }
01823 
01824                      proxy_userid=NULL;
01825                      for (pl=proxy_list; pl; pl=pl->next)
01826                      {
01827                             if (proxy_userid)
01828                                    printf("111-DELETE %s\n",
01829                                           proxy_userid);
01830 
01831                             proxy_userid=pl->userid;
01832                      }
01833 
01834                      if (proxy_userid)
01835                             printf("111 DELETE %s\n", proxy_userid);
01836                      else
01837                             printf("200 Ok\n");
01838 
01839                      rset(pcp);
01840                      return (0);
01841               }
01842 
01843               printf("500 There's nothing to commit.\n");
01844               return (0);
01845        }
01846 
01847        if (strcasecmp(q, "CANCEL") == 0)
01848        {
01849               int errcode;
01850 
01851               if (check_acl(acl_flags, PCP_ACL_MODIFY))
01852                      return (0);
01853 
01854               q=strtok(NULL, " ");
01855               if (!q)
01856                      printf("500 Syntax error\n");
01857               else if (pcp_cancel(pcp, q, &errcode))
01858                      error(errcode);
01859               else
01860                      printf("200 Cancelled\n");
01861               return (0);
01862        }
01863 
01864        if (strcasecmp(q, "UNCANCEL") == 0)
01865        {
01866               struct PCP_uncancel unc;
01867               struct uncancel_list *list=NULL, **tail= &list;
01868               struct uncancel_list *p;
01869 
01870               if (check_acl(acl_flags, PCP_ACL_MODIFY))
01871                      return (0);
01872 
01873               memset(&unc, 0, sizeof(unc));
01874               unc.uncancel_conflict_callback=uncancel_callback;
01875               unc.uncancel_conflict_callback_ptr=&tail;
01876 
01877               q=strtok(NULL, " ");
01878               if (!q)
01879                      printf("500 Syntax error\n");
01880               else if (pcp_uncancel(pcp, q,
01881                                   (conflict_flag ? PCP_OK_CONFLICT:0)|
01882                                   (force_flag ? PCP_OK_PROXY_ERRORS:0),
01883                                   &unc))
01884               {
01885                      if (unc.errcode == PCP_ERR_CONFLICT && list)
01886                      {
01887                             for (p=list; p; p=p->next)
01888                             {
01889                                    char from_buf[15];
01890                                    char to_buf[15];
01891 
01892                                    pcp_gmtimestr(p->from, from_buf);
01893                                    pcp_gmtimestr(p->to, to_buf);
01894 
01895                                    printf("403%c%s %s %s %s conflicts.\n",
01896                                           p->next ? '-':' ',
01897                                           p->addr,
01898                                           from_buf,
01899                                           to_buf,
01900                                           p->id);
01901                             }
01902                      }
01903                      else
01904                             error(unc.errcode);
01905               }
01906               else
01907                      printf("200 Uncancelled\n");
01908 
01909               while((p=list) != NULL)
01910               {
01911                      list=p->next;
01912                      free(p->addr);
01913                      free(p->id);
01914                      free(p);
01915               }
01916               return (0);
01917        }
01918 
01919        printf("500 Syntax error\n");
01920        return (0);
01921 }
01922 
01923 static int check_acl(int flags, int bit)
01924 {
01925        if (flags & bit)
01926               return (0);
01927 
01928        printf("500 Permission denied.\n");
01929        return (1);
01930 }
01931 
01932 static RETSIGTYPE catch_sig(int sig_num)
01933 {
01934        termsig=1;
01935        signal(SIGALRM, catch_sig);
01936        alarm(2);
01937 
01938 #if RETSIGTYPE != void
01939        return (0);
01940 #endif
01941 }
01942 
01943 static void setsigs()
01944 {
01945        struct sigaction sa;
01946 
01947        memset(&sa, 0, sizeof(sa));
01948 
01949        sa.sa_handler=catch_sig;
01950        sigaction(SIGHUP, &sa, NULL);
01951        sigaction(SIGTERM, &sa, NULL);
01952        sigaction(SIGINT, &sa, NULL);
01953 }
01954 
01955 struct get_acl {
01956        const char *who;
01957        int flags;
01958 };
01959 
01960 static int get_acl_callback(const char *w, int f, void *dummy)
01961 {
01962        struct get_acl *ga=(struct get_acl *)dummy;
01963 
01964        if (addrcmp(w, ga->who) == 0)
01965               ga->flags=f;
01966        return (0);
01967 }
01968 
01969 static void mainloop(struct PCP *pcp)
01970 {
01971        int c;
01972        struct pcpdtimer inactivity_timeout;
01973        int my_acl_flags=PCP_ACL_MODIFY|PCP_ACL_CONFLICT|
01974               PCP_ACL_LIST|PCP_ACL_RETR;
01975 
01976        deleted_eventid=NULL;
01977        memset(&new_commit, 0, sizeof(new_commit));
01978        new_commit_times=NULL;
01979        new_commit_participants=NULL;
01980        new_commit_participants_buf=NULL;
01981 
01982        termsig=0;
01983 
01984        setsigs();
01985 
01986        inp_ptr=0;
01987        inp_left=0;
01988        need_rset=0;
01989 
01990        time(&prev_time);
01991 
01992        pcpdtimer_init(&inactivity_timeout);
01993        inactivity_timeout.handler=inactive;
01994 
01995        if (proxy_userid)
01996        {
01997               struct get_acl ga;
01998 
01999               ga.who=proxy_userid;
02000               ga.flags=0;
02001               if (pcp_has_acl(pcp))
02002               {
02003                      if (pcp_list_acl(pcp, get_acl_callback, &ga) == 0)
02004                      {
02005                             if (ga.flags == 0)
02006                             {
02007                                    ga.who="public";
02008                                    if (pcp_list_acl(pcp, get_acl_callback,
02009                                                   &ga))
02010                                           ga.flags=0;
02011                             }
02012                      }
02013                      else ga.flags=0;
02014               }
02015               my_acl_flags=ga.flags;
02016        }
02017 
02018        do
02019        {
02020               char *p;
02021 
02022               input_line_len=0;
02023               pcpdtimer_install(&inactivity_timeout, 30 * 60);
02024 
02025               for (;;)
02026               {
02027 
02028 
02029                      c=inputchar(pcp);
02030 
02031                      if (termsig || c == '\n')
02032                             break;
02033                      input_buffer[input_line_len++]=c;
02034               }
02035               if (termsig)
02036                      break;
02037 
02038               input_buffer[input_line_len]=0;
02039 
02040               for (p=input_buffer; *p; p++)
02041                      if (isspace((int)(unsigned char)*p))
02042                             *p=' ';
02043               pcpdtimer_triggered(&inactivity_timeout);
02044               /* Cancel inactivity_timeout for the duration of the command */
02045 
02046        } while (doline(pcp, input_buffer, my_acl_flags) == 0 && !termsig);
02047        alarm(0);
02048        free(input_buffer);
02049        rset(pcp);
02050 }
02051 
02052 /*
02053 ** Start listening on a socket for connections
02054 */
02055 
02056 static void accept_pcpd(int, int, int, int);
02057 
02058 static void start()
02059 {
02060        int pubsock;
02061        int privsock;
02062 
02063        if ((pubsock=pcp_mksocket(PUBDIR, "PCPDLOCAL")) < 0)
02064        {
02065               exit(1);
02066        }
02067 
02068        if ((privsock=pcp_mksocket(PRIVDIR, "PCPDLOCAL")) < 0)
02069        {
02070               exit (1);
02071        }
02072 
02073 #if USE_NOCLDWAIT
02074        {
02075               struct sigaction sa;
02076 
02077               memset(&sa, 0, sizeof(sa));
02078               sa.sa_handler=SIG_IGN;
02079               sa.sa_flags=SA_NOCLDWAIT;
02080               sigaction(SIGCHLD, &sa, NULL);
02081        }
02082 #else
02083        signal(SIGCHLD, SIG_IGN);
02084 #endif
02085 
02086        for (;;)
02087        {
02088               fd_set fds;
02089               struct timeval tv;
02090               int rc;
02091 
02092               FD_ZERO(&fds);
02093               FD_SET(pubsock, &fds);
02094               FD_SET(privsock, &fds);
02095 
02096               tv.tv_sec=authtoken_check();
02097               tv.tv_usec=0;
02098 
02099               if ((rc=select ( (pubsock > privsock ? pubsock:privsock)+1,
02100                              &fds, NULL, NULL, &tv)) < 0)
02101               {
02102                      perror("pcpd: select");
02103                      continue;
02104               }
02105 
02106               if (rc == 0)
02107                      continue;
02108 
02109               if (FD_ISSET(pubsock, &fds))
02110                      accept_pcpd(pubsock, pubsock, privsock, 0);
02111 
02112               if (FD_ISSET(privsock, &fds))
02113                      accept_pcpd(privsock, pubsock, privsock, 1);
02114        }
02115 }
02116 
02117 struct userid_info {
02118        char *userid;
02119        int isproxy;
02120 } ;
02121 
02122 static int callback_userid(struct userid_callback *a, void *vp)
02123 {
02124        struct userid_info *uinfo=(struct userid_info *)vp;
02125        char *u=strdup(a->userid);
02126        struct stat stat_buf;
02127 
02128        if (!u)
02129               return (-1);
02130 
02131        if (stat(a->homedir, &stat_buf) < 0)
02132        {
02133               free(u);
02134               return (-1);
02135        }
02136 
02137        if (stat_buf.st_mode & S_ISVTX)
02138        {
02139               free(u);
02140               errno=EAGAIN;
02141               return (1);
02142        }
02143 
02144        uinfo->userid=u;
02145        return (0);
02146 }
02147 
02148 static int callback_login(struct userid_callback *a, void *vp)
02149 {
02150        struct userid_info *uinfo=(struct userid_info *)vp;
02151        struct stat stat_buf;
02152        time_t t;
02153        char curdir[1024];
02154        char *token=NULL;
02155 
02156        if (stat(a->homedir, &stat_buf) < 0)
02157               return (-1);
02158 
02159        if (stat_buf.st_mode & S_ISVTX)
02160        {
02161               errno=EAGAIN;
02162               return (1);
02163        }
02164 
02165        time(&t);
02166        if (!uinfo->isproxy)
02167        {
02168               token=authtoken_create(uinfo->userid, t);
02169               if (!token)
02170               {
02171                      fprintf(stderr, "NOTICE: authtoken_create() failed.\n");
02172                      maildir_cache_cancel();
02173                      return (1);
02174               }
02175        }
02176 
02177        maildir_cache_start();
02178 
02179        libmail_changeuidgid(a->uid, getgid());
02180 
02181        if (chdir(a->homedir) < 0)
02182        {
02183               free(token);
02184               fprintf(stderr, "NOTICE: chdir(%s) failed: %s\n", a->homedir,
02185                      strerror(errno));
02186               maildir_cache_cancel();
02187               exit(1);
02188        }
02189 
02190        if (chdir(a->maildir && *a->maildir ? a->maildir:"Maildir") < 0)
02191        {
02192               free(token);
02193               fprintf(stderr, "NOTICE: chdir(Maildir) failed: %s\n",
02194                      strerror(errno));
02195               maildir_cache_cancel();
02196               exit(1);
02197        }
02198 
02199        mkdir("calendar", 0700);
02200        if (chdir("calendar") < 0)
02201        {
02202               free(token);
02203               fprintf(stderr, "NOTICE: chdir(calendar) failed: %s\n",
02204                      strerror(errno));
02205               maildir_cache_cancel();
02206               exit(1);
02207        }
02208 
02209        curdir[sizeof(curdir)-1]=0;
02210        if (getcwd(curdir, sizeof(curdir)-1) == 0)
02211        {
02212               fprintf(stderr, "NOTICE: getcwd() failed: %s\n",
02213                      strerror(errno));
02214               maildir_cache_cancel();
02215               exit(1);
02216        }
02217 
02218        maildir_cache_save(uinfo->userid, t, curdir, a->uid, getgid());
02219 
02220        alarm(0);
02221        if (!uinfo->isproxy)
02222        {
02223               printf("102 %s logged in.\n", token);
02224               free(token);
02225        }
02226        return (0);
02227 }
02228 
02229 static char *login(int, int *);
02230 
02231 static int accept_sock(int sock)
02232 {
02233        struct sockaddr_un saddr;
02234        socklen_t saddr_len;
02235 
02236        saddr_len=sizeof(saddr);
02237 
02238        return (accept(sock, (struct sockaddr *)&saddr, &saddr_len));
02239 }
02240 
02241 static void accept_pcpd(int sock, int pubsock, int privsock, int flag)
02242 {
02243        int fd;
02244        pid_t pid;
02245        struct PCP *pcp;
02246 
02247        if ((fd=accept_sock(sock)) < 0)
02248               return;
02249 
02250        if (fcntl(fd, F_SETFL, 0) < 0)
02251        {
02252               fprintf(stderr, "CRIT: fcntl() failed: %s\n", strerror(errno));
02253               close(fd);
02254               return;
02255        }
02256 
02257        maildir_cache_purge();
02258        pid=fork();
02259 
02260        if (pid < 0)
02261        {
02262               fprintf(stderr, "CRIT: fork() failed: %s\n", strerror(errno));
02263               close(fd);
02264               return;
02265        }
02266 
02267        if (pid)
02268        {
02269               close(fd);
02270               return;       /* Parent resumes listening */
02271        }
02272 
02273        /* child */
02274        signal(SIGCHLD, SIG_DFL);
02275 
02276        close(pubsock);
02277        close(privsock);
02278 
02279        close(0);
02280        if (dup(fd) != 0)
02281               exit(0);
02282        close(1);
02283        if (dup(fd) != 1)
02284               exit(0);
02285        close(fd);
02286        userid=login(flag, &flag);
02287 
02288        pcp=pcp_open_dir(".", userid);
02289 
02290        if (pcp && flag && pcp_cleanup(pcp))
02291        {
02292               pcp_close(pcp);
02293               fprintf(stderr, "CRIT: pcp_cleanup failed\n");
02294               pcp=NULL;
02295        }
02296 
02297        if (!pcp)
02298        {
02299               fprintf(stderr, "CRIT: pcp_open_dir failed\n");
02300               perror("pcp_open_dir");
02301               exit(1);
02302        }
02303 
02304        mainloop(pcp);
02305        exit(0);
02306 }
02307 
02308 struct relogin_struct {
02309        time_t when;
02310        int needauthtoken;
02311        const char *userid;
02312 } ;
02313 
02314 static int callback_cache_search(uid_t u, gid_t g, const char *dir, void *vp)
02315 {
02316        struct relogin_struct *rs=(struct relogin_struct *)vp;
02317        time_t login_time, now;
02318        int reset_flag;
02319        char *token=NULL;
02320 
02321        login_time=rs->when;
02322        time(&now);
02323 
02324        reset_flag= login_time <= now - TIMEOUT;
02325 
02326        if (reset_flag)
02327        {
02328               if (rs->needauthtoken)
02329               {
02330                      token=authtoken_create(rs->userid, now);
02331                      if (!token)
02332                      {
02333                             fprintf(stderr,
02334                                    "ALERT: authtoken_create() failed.\n");
02335                             return (1);
02336                      }
02337               }
02338               maildir_cache_start();
02339        }
02340 
02341        libmail_changeuidgid(u, g);
02342 
02343        if (chdir(dir) < 0)
02344        {
02345               maildir_cache_cancel();
02346               fprintf(stderr, "NOTICE: chdir(%s) failed: %s\n", dir, strerror(errno));
02347               return (-1);
02348        }
02349 
02350        alarm(0);
02351        if (reset_flag)
02352        {
02353               maildir_cache_save(rs->userid, now, dir, u, g);
02354               if (rs->needauthtoken)
02355               {
02356                      printf("102 %s logged in.\n", token);
02357                      free(token);
02358               }
02359        }
02360        else if (rs->needauthtoken) /* Not a proxy connection */
02361               printf("200 Ok\n");
02362        return (0);
02363 }
02364 
02365 static char *login(int isprivate,
02366                  int *flag   /* Cleanup requested */
02367                  )
02368 {
02369        struct userid_info uinfo;
02370 
02371        proxy_userid=NULL;
02372        *flag=0;
02373        memset(&uinfo, 0, sizeof(uinfo));
02374        alarm(300);   /* Better log in in five minutes */
02375        for (;;)
02376        {
02377               int c;
02378               char *p;
02379 
02380               input_line_len=0;
02381               for (;;)
02382               {
02383                      c=inputchar(NULL);
02384                      if (c == EOF)
02385                             exit(0);
02386 
02387                      if (c == '\n')
02388                             break;
02389                      input_buffer[input_line_len]=c;
02390                      if (input_line_len < 1024)
02391                             ++input_line_len;
02392               }
02393               input_buffer[input_line_len]=0;
02394 
02395               for (p=input_buffer; *p &&
02396                           isspace((int)(unsigned char)*p); p++)
02397                      ;
02398 
02399               if (strncasecmp(p, "PASSWORD", 8) == 0 && !isprivate &&
02400                   isspace((int)(unsigned char)p[8]) && uinfo.userid)
02401               {
02402                      for (p += 9; isspace((int)(unsigned char)*p); p++)
02403                             ;
02404 
02405                      if (*p)
02406                      {
02407                             int rc;
02408                             char *q, *r;
02409 
02410                             for (q=r=p; *q; q++)
02411                                    if (!isspace((int)(unsigned char)*q))
02412                                           r=q+1;
02413                             *r=0;
02414 
02415                             rc=authpcp_login(uinfo.userid, p,
02416                                            callback_login, &uinfo);
02417 
02418                             if (rc)
02419                             {
02420                                    printf("%s %s\n",
02421                                           rc < 0 ? "501":"401",
02422                                           strerror(errno));
02423                                    continue;
02424                             }
02425                             *flag=1;
02426                             break;
02427                      }
02428               }
02429 
02430               for (p=input_buffer; *p; p++)
02431                      if (isspace((int)(unsigned char)*p))
02432                             *p=' ';
02433 
02434               p=strtok(input_buffer, " ");
02435 
02436               if (p && strcasecmp(p, "CAPABILITY") == 0)
02437               {
02438                      printf("100 PCP1\n");
02439                      continue;
02440               }
02441               else if (p && strcasecmp(p, "USERID") == 0 &&
02442                   uinfo.userid == NULL)
02443               {
02444                      if ((p=strtok(NULL, " ")) != NULL)
02445                      {
02446                             int rc= authpcp_userid(p, callback_userid,
02447                                                  &uinfo);
02448 
02449                             if (rc)
02450                             {
02451                                    printf("%s %s\n",
02452                                           rc < 0 ? "501":"401",
02453                                           strerror(errno));
02454                                    continue;
02455                             }
02456 
02457                             printf("301 Ok, waiting for password.\n");
02458                             continue;
02459                      }
02460               }
02461               else if (p && strcasecmp(p, "PROXY") == 0 && uinfo.userid &&
02462                       isprivate)
02463               {
02464                      if ((p=strtok(NULL, " ")) != 0)
02465                      {
02466                             struct relogin_struct rs;
02467                             time_t now;
02468                             int rc;
02469 
02470                             if (proxy_userid)
02471                                    free(proxy_userid);
02472                             if ((proxy_userid=auth_choplocalhost(p))
02473                                 == NULL)
02474                             {
02475                                    printf("400 %s\n", strerror(errno));
02476                                    continue;
02477                             }
02478 
02479                             rs.needauthtoken=0;
02480                             rs.userid=uinfo.userid;
02481 
02482                             time(&now);
02483 
02484                             rc=maildir_cache_search(uinfo.userid, now,
02485                                                  callback_cache_search,
02486                                                  &rs);
02487                             if (rc == 0)
02488                             {
02489                                    alarm(0);
02490                                    printf("200 PROXY ok\n");
02491                                    break;
02492                             }
02493                             now -= TIMEOUT;
02494 
02495                             rc=maildir_cache_search(uinfo.userid, now,
02496                                                  callback_cache_search,
02497                                                  &rs);
02498                             if (rc == 0)
02499                             {
02500                                    alarm(0);
02501                                    printf("200 PROXY ok\n");
02502                                    break;
02503                             }
02504 
02505                             uinfo.isproxy=1;
02506                             rc=authpcp_userid(uinfo.userid, callback_login,
02507                                             &uinfo);
02508                             if (rc)
02509                             {
02510                                    fprintf(stderr,
02511                                           "CRIT: auth_userid() failed\n");
02512                                    exit(1);
02513                             }
02514                             alarm(0);
02515                             printf("200 PROXY ok\n");
02516                             break;
02517                      }
02518 
02519               }
02520               else if (p && strcasecmp(p, "RELOGIN") == 0 && uinfo.userid &&
02521                       !isprivate)
02522               {
02523                      if ((p=strtok(NULL, " ")) != 0)
02524                      {
02525                             struct relogin_struct rs;
02526                             int rc;
02527 
02528                             rs.needauthtoken=1;
02529                             rs.userid=uinfo.userid;
02530                             if (authtoken_verify(uinfo.userid, p,
02531                                                &rs.when))
02532                             {
02533                                    printf("500 Invalid authentication token.\n");
02534                                    continue;
02535                             }
02536 
02537                             rc=maildir_cache_search(uinfo.userid, rs.when,
02538                                                  callback_cache_search,
02539                                                  &rs);
02540                             if (rc == 0)
02541                                    break;
02542 
02543                             /*
02544                             ** Couldn't find anything in the login cache.
02545                             ** call the userid function with the login
02546                             ** callback.
02547                             ** This'll initialize lotsa other stuff, but
02548                             ** we don't care.
02549                             */
02550 
02551                             rc=authpcp_userid(uinfo.userid,
02552                                             callback_login,
02553                                             &uinfo);
02554 
02555                             if (rc)
02556                             {
02557                                    fprintf(stderr,
02558                                           "NOTICE: auth_userid() failed.\n");
02559                                    printf("400 Internal failure - try again later.\n");
02560                                    continue;
02561                             }
02562                             break;
02563                      }
02564               }
02565               else if (p && strcasecmp(p, "QUIT") == 0)
02566               {
02567                      printf("200 Ok\n");
02568                      exit (0);
02569               }
02570               printf("500 Syntax error\n");
02571        }
02572        return (uinfo.userid);
02573 }
02574 
02575 int main(int argc, char **argv)
02576 {
02577        int argn=1;
02578        static const char * const authvars[]={NULL};
02579 
02580        signal(SIGPIPE, SIG_IGN);
02581        umask(022);
02582 
02583        if (argn >= argc)
02584        {
02585               struct PCP *pcp;
02586 
02587               pcp=open_calendar(NULL);
02588 
02589               mainloop(pcp);
02590               exit(0);
02591        }
02592 
02593        maildir_cache_init(TIMEOUT * 2, CACHEDIR, LOCALCACHEOWNER, authvars);
02594 
02595        if (strcmp(argv[argn], "server") == 0)
02596        {
02597               struct group *gr;
02598 
02599               if (chdir(CALENDARDIR) < 0)
02600               {
02601                      perror(CALENDARDIR);
02602                      exit(1);
02603               }
02604               gr=getgrnam(MAILGROUP);
02605 
02606               if (!gr)
02607               {
02608                      fprintf(stderr, "Unknown group: %s\n", MAILGROUP);
02609                      exit(1);
02610               }
02611 
02612               authtoken_init();
02613               libmail_changeuidgid(getuid(), gr->gr_gid);
02614               start();
02615        }
02616        else if (strcmp(argv[argn], "login") == 0 ||
02617                strcmp(argv[argn], "slogin") == 0)
02618        {
02619               struct PCP *pcp;
02620               int flag;
02621               struct group *gr;
02622 
02623               gr=getgrnam(MAILGROUP);
02624 
02625               if (!gr)
02626               {
02627                      fprintf(stderr, "Unknown group: %s\n", MAILGROUP);
02628                      exit(1);
02629               }
02630               libmail_changeuidgid(getuid(), gr->gr_gid);
02631 
02632               if (chdir(CALENDARDIR) < 0)
02633               {
02634                      perror(CALENDARDIR);
02635                      exit(1);
02636               }
02637 
02638               authtoken_init();
02639               userid=login(strcmp(argv[argn], "login"), &flag);
02640 
02641               pcp=pcp_open_dir(".", userid);
02642 
02643               if (pcp && flag && pcp_cleanup(pcp))
02644               {
02645                      pcp_close(pcp);
02646                      fprintf(stderr, "CRIT: pcp_cleanup failed\n");
02647                      pcp=NULL;
02648               }
02649 
02650               if (!pcp)
02651               {
02652                      fprintf(stderr, "CRIT: pcp_open_dir failed\n");
02653                      perror("pcp_open_dir");
02654                      exit(1);
02655               }
02656 
02657               mainloop(pcp);
02658               exit(0);
02659        }
02660        else if (strcmp(argv[argn], "open") == 0)
02661        {
02662               ++argn;
02663               if (argn < argc)
02664               {
02665                      struct PCP *pcp;
02666 
02667                      pcp=open_calendar(argv[argn]);
02668 
02669                      mainloop(pcp);
02670                      exit(0);
02671               }
02672        }
02673        fprintf(stderr, "Usage: %s (server|open [path])\n", argv[0]);
02674        exit(0); /* exit(1) breaks Courier rpm %preun script */
02675        return (0);
02676 }