Back to index

courier  0.68.2
pcpnet.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2001-2002 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 <errno.h>
00012 #include <signal.h>
00013 #include <fcntl.h>
00014 #include <unistd.h>
00015 #include <ctype.h>
00016 #include <time.h>
00017 #include <sys/types.h>
00018 #include <sys/socket.h>
00019 #include <sys/stat.h>
00020 #include <sys/time.h>
00021 #include <sys/un.h>
00022 #include <rfc822/rfc822hdr.h>
00023 #include "pcp.h"
00024 #include "calendardir.h"
00025 
00026 #if HAVE_DIRENT_H
00027 #include <dirent.h>
00028 #else
00029 #define dirent direct
00030 #if HAVE_SYS_NDIR_H
00031 #include <sys/ndir.h>
00032 #endif
00033 #if HAVE_SYS_DIR_H
00034 #include <sys/dir.h>
00035 #endif
00036 #if HAVE_NDIR_H
00037 #include <ndir.h>
00038 #endif
00039 #endif
00040 
00041 #define HOSTNAMELEN 256
00042 
00043 #define EVENTID_MAXLEN 512
00044 #define ADDR_MAXLEN 512
00045 
00046 #define EVENTID_SSCANF "%511s"
00047 #define ADDR_SSCANF "%511s"
00048 
00049 struct PCPnet {
00050        struct PCP pcp;
00051        char *username;
00052        char *authtoken;
00053        char *sockname;
00054        int fd;
00055 
00056        char *readbuf;
00057        size_t readbuflen;
00058 
00059        char *readptr;
00060        size_t readleft;
00061 
00062        int haserrmsg;
00063 } ;
00064 
00065 struct PCPnet_new_eventid {
00066        struct PCP_new_eventid eventid;
00067        int isbooked;
00068 } ;
00069 
00070 static void pcp_close_quit_net(struct PCPnet *);
00071 static void pcp_close_net(struct PCPnet *);
00072 static int cleanup(struct PCPnet *);
00073 
00074 static struct PCP_new_eventid *neweventid(struct PCPnet *,
00075                                      const char *,
00076                                      struct PCP_save_event *);
00077 static void destroyeventid(struct PCPnet *, struct PCPnet_new_eventid *);
00078 
00079 static int commitevent(struct PCPnet *, struct PCPnet_new_eventid *,
00080                      struct PCP_commit *);
00081 static int bookevent(struct PCPnet *, struct PCPnet_new_eventid *,
00082                    struct PCP_commit *);
00083 
00084 static int listallevents(struct PCPnet *, struct PCP_list_all *);
00085 
00086 static int cancelevent(struct PCPnet *, const char *, int *);
00087 static int uncancelevent(struct PCPnet *, const char *,
00088                       int, struct PCP_uncancel *);
00089 static int deleteevent(struct PCPnet *, struct PCP_delete *);
00090 static int retrevent(struct PCPnet *, struct PCP_retr *);
00091 static int setacl(struct PCPnet *, const char *, int);
00092 static int listacl(struct PCPnet *,
00093                  int (*)(const char *, int, void *),
00094                  void *);
00095 static void noop(struct PCPnet *);
00096 
00097 static const char *getauthtoken(struct PCPnet *pcp)
00098 {
00099        return (pcp->authtoken);
00100 }
00101 
00102 static const char *errmsg(struct PCPnet *pcp)
00103 {
00104        if (pcp->haserrmsg)
00105               return (pcp->readbuf);
00106        return (strerror(errno));
00107 }
00108 
00109 static struct PCPnet *mkpcp(const char *username)
00110 {
00111        struct PCPnet *pd=(struct PCPnet *)malloc(sizeof(struct PCPnet));
00112        const char *p;
00113 
00114        if (!pd)
00115               return (NULL);
00116 
00117        if (!*username)
00118        {
00119               free(pd);
00120               errno=EIO;
00121               return (NULL);
00122        }
00123 
00124        for (p=username; *p; p++)
00125               if (isspace((int)(unsigned char)*p))
00126               {
00127                      free(pd);
00128                      errno=EIO;
00129                      return (NULL);
00130               }
00131 
00132        memset(pd, 0, sizeof(*pd));
00133 
00134        pd->fd= -1;
00135        pd->username=strdup(username);
00136        if (!pd->username)
00137        {
00138               free(pd);
00139               return (NULL);
00140        }
00141 
00142        pd->pcp.authtoken_func=(const char *(*)(struct PCP *))getauthtoken;
00143        pd->pcp.close_func= (void (*)(struct PCP *)) pcp_close_quit_net;
00144        pd->pcp.cleanup_func= (int (*)(struct PCP *)) cleanup;
00145 
00146        pd->pcp.create_new_eventid_func=
00147               (struct PCP_new_eventid *(*)(struct PCP *, const char *,
00148                                         struct PCP_save_event *))
00149               neweventid;
00150 
00151        pd->pcp.destroy_new_eventid_func=
00152               (void (*)(struct PCP *, struct PCP_new_eventid *))
00153               destroyeventid;
00154 
00155        pd->pcp.commit_func=
00156               (int (*)(struct PCP *, struct PCP_new_eventid *,
00157                       struct PCP_commit *))
00158               commitevent;
00159 
00160        pd->pcp.book_func=
00161               (int (*)(struct PCP *, struct PCP_new_eventid *,
00162                       struct PCP_commit *))
00163               bookevent;
00164 
00165        pd->pcp.list_all_func=
00166               (int (*)(struct PCP *, struct PCP_list_all *))
00167               listallevents;
00168 
00169        pd->pcp.cancel_func=
00170               (int (*)(struct PCP *, const char *, int *))
00171               cancelevent;
00172 
00173        pd->pcp.uncancel_func=
00174               (int (*)(struct PCP *, const char *, int,
00175                       struct PCP_uncancel *))
00176               uncancelevent;
00177 
00178        pd->pcp.delete_func=
00179               (int (*)(struct PCP *, struct PCP_delete *))
00180               deleteevent;
00181 
00182        pd->pcp.retr_func=
00183               (int (*)(struct PCP *, struct PCP_retr *))
00184               retrevent;
00185 
00186        pd->pcp.errmsg_func=
00187               (const char *(*)(struct PCP *))
00188               errmsg;
00189 
00190        pd->pcp.noop_func=(void (*)(struct PCP *))noop;
00191 
00192        pd->pcp.acl_func=
00193               (int (*)(struct PCP *, const char *, int))setacl;
00194        pd->pcp.listacl_func=
00195               (int (*)(struct PCP *, int (*)(const char *, int, void *),
00196                       void *))listacl;
00197 
00198        return (pd);
00199 }
00200 
00201 struct sock_list {
00202        struct sock_list *next;
00203        char *filename;
00204 } ;
00205 
00206 static int cmp_str(const void *a, const void *b)
00207 {
00208        return (strcmp(*(const char **)a, *(const char **)b));
00209 }
00210 
00211 static int dowrite(struct PCPnet *pcp, const char *s, int l)
00212 {
00213        if (l <= 0)
00214               l=strlen(s);
00215 
00216        if (pcp->fd < 0)
00217        {
00218               errno=ENETDOWN;
00219               return (-1);
00220        }
00221 
00222        while (l)
00223        {
00224               int n=write(pcp->fd, s, l);
00225 
00226               if (n <= 0)
00227               {
00228                      errno=ENETDOWN;
00229                      close(pcp->fd);
00230                      pcp->fd= -1;
00231                      return (-1);
00232               }
00233 
00234               s += n;
00235               l -= n;
00236        }
00237        return (0);
00238 }
00239 
00240 static int readch(struct PCPnet *pcp, size_t n)
00241 {
00242        if (pcp->readleft == 0)
00243        {
00244               int l;
00245               struct timeval tv;
00246               fd_set fds;
00247 
00248               /* Read the next chunk after the current line :-) */
00249 
00250               if (n + BUFSIZ > pcp->readbuflen)
00251               {
00252                      size_t nn=n+BUFSIZ;
00253                      char *p= pcp->readbuf ?
00254                             realloc(pcp->readbuf, nn):malloc(nn);
00255                      if (!p)
00256                      {
00257                             close(pcp->fd);
00258                             pcp->fd= -1;
00259                             return (-1);
00260                      }
00261                      pcp->readbuf=p;
00262                      pcp->readbuflen=nn;
00263               }
00264 
00265               pcp->readptr=pcp->readbuf + n;
00266 
00267               FD_ZERO(&fds);
00268               FD_SET(pcp->fd, &fds);
00269               tv.tv_sec=300;
00270               tv.tv_usec=0;
00271               if (select(pcp->fd+1, &fds, NULL, NULL, &tv) <= 0)
00272               {
00273                      errno=ETIMEDOUT;
00274                      close(pcp->fd);
00275                      pcp->fd= -1;
00276                      return (EOF);
00277               }
00278               l=read(pcp->fd, pcp->readptr, BUFSIZ);
00279               if (l <= 0)
00280               {
00281                      if (l == 0)
00282                             errno=0;
00283                      close(pcp->fd);
00284                      pcp->fd= -1;
00285                      errno=ECONNRESET;
00286                      return (EOF);
00287               }
00288               pcp->readleft=l;
00289        }
00290 
00291        --pcp->readleft;
00292        return ((int)(unsigned char)*pcp->readptr++);
00293 }
00294 
00295 static int getfullreply(struct PCPnet *pcp)
00296 {
00297        size_t n=0;
00298        int ch;
00299 
00300        for (;;)
00301        {
00302               size_t nn=n;
00303 
00304               while ((ch=readch(pcp, nn)) != EOF)
00305               {
00306                      if (ch == '\n')
00307                             break;
00308                      pcp->readbuf[nn++]=ch;
00309               }
00310 
00311               if (ch == EOF)
00312                      return (-1);
00313 
00314               if (nn-n >= 4 &&
00315                   isdigit((int)(unsigned char)pcp->readbuf[n]) &&
00316                   isdigit((int)(unsigned char)pcp->readbuf[n+1]) &&
00317                   isdigit((int)(unsigned char)pcp->readbuf[n+2]) &&
00318                   isspace((int)(unsigned char)pcp->readbuf[n+3]))
00319               {
00320                      pcp->readbuf[nn]=0;
00321                      break;
00322               }
00323               n= ++nn;
00324        }
00325 
00326        return (0);
00327 }
00328 
00329 static int getonelinereply(struct PCPnet *pcp)
00330 {
00331        size_t nn;
00332        int islast;
00333 
00334        nn=0;
00335        for (;;)
00336        {
00337               int ch;
00338 
00339               while ((ch=readch(pcp, nn)) != EOF)
00340               {
00341                      if (ch == '\n')
00342                             break;
00343                      pcp->readbuf[nn++]=ch;
00344                      if (nn >= 8192)
00345                             nn=8192;
00346               }
00347               pcp->readbuf[nn]=0;
00348               if (ch == EOF)
00349                      return (-1);
00350 
00351               if (!isdigit((int)(unsigned char)pcp->readbuf[0])
00352                   || !isdigit((int)(unsigned char)pcp->readbuf[1])
00353                   || !isdigit((int)(unsigned char)pcp->readbuf[2]))
00354               {
00355                      nn=0;
00356                      continue;
00357               }
00358               islast= pcp->readbuf[3] != '-';
00359               break;
00360        }
00361        return (islast);
00362 }
00363 
00364 
00365 static int docmd(struct PCPnet *pcp, const char *cmd, int cmdl)
00366 {
00367        if (dowrite(pcp, cmd, cmdl) < 0)
00368               return (-1);
00369        return (getfullreply(pcp));
00370 }
00371 
00372 static int checkstatus(struct PCPnet *pcp, int *errcode)
00373 {
00374        const char *p=strrchr(pcp->readbuf, '\n');
00375        int n;
00376 
00377        if (p)
00378               ++p;
00379        else
00380               p=pcp->readbuf;
00381        n=atoi(p);
00382        if (errcode)
00383               switch (n) {
00384               case 504:
00385                      *errcode=PCP_ERR_EVENTNOTFOUND;
00386                      break;
00387               case 506:
00388                      *errcode=PCP_ERR_EVENTLOCKED;
00389                      break;
00390               }
00391        return (n);
00392 }
00393 
00394 static char *getword(struct PCPnet *pcp, char **p)
00395 {
00396        char *q;
00397 
00398        while (**p && isspace((int)(unsigned char)**p))
00399               ++*p;
00400 
00401        if (!**p)
00402               return (NULL);
00403        q= *p;
00404 
00405        while (**p && !isspace((int)(unsigned char)**p))
00406               ++*p;
00407 
00408        if (**p)
00409        {
00410               **p=0;
00411               ++*p;
00412        }
00413        return (q);
00414 }
00415 
00416 /* Parse 102 response */
00417 
00418 static int parseauthtoken(struct PCPnet *pcp)
00419 {
00420        char *p=pcp->readbuf;
00421        char *q;
00422 
00423        getword(pcp, &p);    /* skip 102 */
00424 
00425        q=getword(pcp, &p);
00426 
00427        if (!q)
00428        {
00429               errno=EIO;
00430               return (-1);
00431        }
00432 
00433        if (pcp->authtoken)
00434               free(pcp->authtoken);
00435 
00436        if ((p=strrchr(pcp->sockname, '/')) != 0)
00437               ++p;
00438        else
00439               p=pcp->sockname;
00440 
00441        if ((pcp->authtoken=malloc(strlen(p)+strlen(q)+2)) == NULL)
00442               return (-1);
00443        strcat(strcat(strcpy(pcp->authtoken, p), "/"), q);
00444        return (0);
00445 }
00446 
00447 /* Parse 100 response */
00448 
00449 static int has100(struct PCPnet *pcp, const char *kw)
00450 {
00451        char *p=pcp->readbuf;
00452        int l = strlen(kw);
00453 
00454        while (*p)
00455        {
00456               while (isdigit((int)(unsigned char)*p))
00457                      ++p;
00458               if (*p != '\n')
00459                      ++p;
00460 
00461               if (strncasecmp(p, kw, l) == 0 &&
00462                   (p[l] == 0 || isspace((int)(unsigned char)p[l])))
00463                      return (1);
00464 
00465               while (*p)
00466                      if (*p++ == '\n')
00467                             break;
00468        }
00469        return (0);
00470 }
00471 
00472 static int doconnect(struct PCPnet *pcp, const char *dir, const char *username,
00473                    const char *sockname,
00474                    const char *clustername,
00475                    char **errmsg)
00476 {
00477        DIR *dirp=opendir(dir);
00478        struct sock_list *l=NULL;
00479        struct dirent *de;
00480        struct sock_list *nl;
00481        unsigned i,cnt=0;
00482        char **a;
00483        int fd;
00484        char *buf;
00485        int clustername_l=clustername ? strlen(clustername):0;
00486 
00487        if (errmsg)
00488               *errmsg=0;
00489 
00490        while (dirp && (de=readdir(dirp)) != NULL)
00491        {
00492               if (strchr(de->d_name, '.'))
00493                      continue;
00494 
00495               if (sockname && strcmp(de->d_name, sockname))
00496                      continue;
00497 
00498               /*
00499               ** When the proxy connection comes in via the proxy cluster,
00500               ** ignore the proxy cluster client's socket, so we don't end
00501               ** up in an infinite loop!
00502               */
00503 
00504               if (clustername)
00505               {
00506                      const char *p=de->d_name;
00507 
00508                      while (p && isdigit((int)(unsigned char)*p))
00509                             ++p;
00510 
00511                      if (strncasecmp(p, clustername, clustername_l) == 0
00512                          && p[clustername_l] == '.')
00513                             continue;
00514               }
00515 
00516               nl=malloc(sizeof(struct sock_list));
00517 
00518               if (!nl || (nl->filename=malloc(strlen(dir)+2+
00519                                           strlen(de->d_name))) == NULL)
00520               {
00521                      if (nl) free(nl);
00522 
00523                      while ((nl=l) != NULL)
00524                      {
00525                             l=nl->next;
00526                             free(nl->filename);
00527                             free(nl);
00528                      }
00529                      return (-1);
00530               }
00531               strcat(strcat(strcpy(nl->filename, dir), "/"), de->d_name);
00532               ++cnt;
00533               nl->next=l;
00534               l=nl;
00535        }
00536 
00537        if (dirp)
00538               closedir(dirp);
00539 
00540        if (!l)
00541        {
00542               errno=ENOENT;
00543               return (-1);
00544        }
00545 
00546        if ((a=malloc(sizeof(char *)*cnt)) == NULL)
00547        {
00548               while ((nl=l) != NULL)
00549               {
00550                      l=nl->next;
00551                      free(nl->filename);
00552                      free(nl);
00553               }
00554               return (-1);
00555        }
00556 
00557        cnt=0;
00558        for (nl=l; nl; nl=nl->next)
00559               a[cnt++]=nl->filename;
00560 
00561        qsort(a, cnt, sizeof(*a), cmp_str);
00562 
00563        fd= -1;
00564 
00565        for (i=0; i<cnt; i++)
00566        {
00567               struct  sockaddr_un skun;
00568               int rc;
00569 
00570               fd=socket(PF_UNIX, SOCK_STREAM, 0);
00571               if (fd < 0)
00572                      break;
00573 
00574               skun.sun_family=AF_UNIX;
00575               strcpy(skun.sun_path, a[i]);
00576 
00577               if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
00578               {
00579                      close(fd);
00580                      fd= -1;
00581                      break;
00582               }
00583 
00584               if ( pcp->sockname )
00585                      free(pcp->sockname);
00586               if ( (pcp->sockname=strdup(a[i])) == NULL)
00587               {
00588                      close(fd);
00589                      fd= -1;
00590                      break;
00591               }
00592 
00593               if ( connect(fd,
00594                           (const struct sockaddr *)&skun,
00595                           sizeof(skun)) == 0)
00596               {
00597                      /* That was easy, we're done. */
00598 
00599                      if (fcntl(fd, F_SETFL, 0) < 0)
00600                      {
00601                             close(fd);
00602                             fd= -1;
00603                             break;
00604                      }
00605               }
00606               else if ( errno != EINPROGRESS && errno != EWOULDBLOCK)
00607               {
00608                      close(fd);
00609                      fd= -1;
00610                      break;
00611               }
00612               else
00613               {
00614                      struct timeval tv;
00615                      fd_set fdr;
00616                      int rc;
00617 
00618                      FD_ZERO(&fdr);
00619                      FD_SET(fd, &fdr);
00620                      tv.tv_sec=30;
00621                      tv.tv_usec=0;
00622 
00623                      rc=select(fd+1, 0, &fdr, 0, &tv);
00624                      if (rc <= 0 || !FD_ISSET(fd, &fdr))
00625                      {
00626                             close(fd);
00627                             fd= -1;
00628                             break;
00629                      }
00630 
00631                      if ( connect(fd, (const struct sockaddr *)&skun,
00632                                  sizeof(skun)))
00633                      {
00634                             if (errno != EISCONN)
00635                             {
00636                                    close(fd);
00637                                    break;
00638                             }
00639                      }
00640 
00641                      if (fcntl(fd, F_SETFL, 0) < 0)
00642                      {
00643                             close(fd);
00644                             break;
00645                      }
00646               }
00647 
00648               pcp->fd=fd;
00649               if (docmd(pcp, "CAPABILITY\n", 0))
00650               {
00651                      fd= -1;
00652                      break;
00653               }
00654 
00655               if ((rc=checkstatus(pcp, NULL)) != 100)
00656               {
00657                      close(fd);
00658                      fd= -1;
00659                      continue;
00660               }
00661 
00662               if (!has100(pcp, "PCP1"))
00663               {
00664                      close(fd);
00665                      fd= -1;
00666                      continue;
00667               }
00668 
00669               buf=malloc(strlen(username)+sizeof("USERID \n"));
00670               if (buf == 0)
00671               {
00672                      close(fd);
00673                      fd= -1;
00674                      break;
00675 
00676               }
00677 
00678               strcat(strcat(strcpy(buf, "USERID "), username), "\n");
00679 
00680               if (docmd(pcp, buf, 0))
00681               {
00682                      fd= -1;
00683                      free(buf);
00684                      break;
00685               }
00686               pcp->fd= -1;
00687               free(buf);
00688 
00689               switch ((rc=checkstatus(pcp, NULL)) / 100) {
00690               case 1:
00691               case 2:
00692               case 3:
00693                      break;
00694               default:
00695                      errno=EIO;
00696                      if (errmsg)
00697                      {
00698                             if (*errmsg)
00699                                    free(*errmsg);
00700                             *errmsg=strdup(pcp->readbuf);
00701                      }
00702                      close(fd);
00703                      fd= -1;
00704                      break;
00705               case 5:
00706                      errno=ENOENT;
00707                      if (errmsg)
00708                      {
00709                             if (*errmsg)
00710                                    free(*errmsg);
00711                             *errmsg=strdup("Calendar not found.");
00712                      }
00713                      close(fd);
00714                      fd= -1;
00715                      continue;
00716               }
00717 
00718               if (rc == 102)
00719               {
00720                      if (parseauthtoken(pcp))
00721                      {
00722                             close(fd);
00723                             fd= -1;
00724                      }
00725                      break;
00726               }
00727               break;
00728        }
00729 
00730        free(a);
00731        while ((nl=l) != NULL)
00732        {
00733               l=nl->next;
00734               free(nl->filename);
00735               free(nl);
00736        }
00737        return (fd);
00738 }
00739 
00740 static struct PCP *setcapabilities(struct PCPnet *, int);
00741 
00742 struct PCP *pcp_open_server(const char *username, const char *password,
00743                          char **errmsg)
00744 {
00745        struct PCPnet *pcp=mkpcp(username);
00746 
00747        if (errmsg)
00748               *errmsg=0;
00749        if (!pcp)
00750               return (NULL);
00751 
00752        if (strchr(username, '\r') || strchr(username, '\n'))
00753        {
00754               errno=EINVAL;
00755               pcp_close_net(pcp);
00756               return (NULL);
00757        }
00758 
00759        if (strchr(password, '\r') || strchr(password, '\n'))
00760        {
00761               errno=EINVAL;
00762               pcp_close_net(pcp);
00763               return (NULL);
00764        }
00765 
00766 
00767        if ((pcp->fd=doconnect(pcp, CALENDARDIR "/public", username, NULL,
00768                             NULL, errmsg)) < 0)
00769        {
00770               pcp_close_net(pcp);
00771               return (NULL);
00772        }
00773 
00774        if (pcp->authtoken == NULL)
00775        {
00776               char *buf;
00777               int rc;
00778 
00779               if (strchr(password, '\n') || strchr(password, '\r'))
00780               {
00781                      errno=EINVAL;
00782                      pcp_close_net(pcp);
00783                      return (NULL);
00784               }
00785 
00786               buf=malloc(strlen(password)+sizeof("PASSWORD \n"));
00787               if (buf == 0)
00788               {
00789                      pcp_close_net(pcp);
00790                      return (NULL);
00791               }
00792 
00793               strcat(strcat(strcpy(buf, "PASSWORD "), password), "\n");
00794 
00795               if (docmd(pcp, buf, 0))
00796               {
00797                      free(buf);
00798                      pcp_close_net(pcp);
00799                      return (NULL);
00800               }
00801               free(buf);
00802 
00803               switch ((rc=checkstatus(pcp, NULL)) / 100) {
00804               case 1:
00805               case 2:
00806               case 3:
00807                      break;
00808               default:
00809                      if (errmsg)
00810                      {
00811                             if (*errmsg)
00812                                    free(*errmsg);
00813                             *errmsg=strdup(pcp->readbuf);
00814                      }
00815                      pcp_close_net(pcp);
00816                      errno=EPERM;
00817                      return (NULL);
00818               }
00819 
00820               if (rc == 102)
00821               {
00822                      if (parseauthtoken(pcp))
00823                      {
00824                             pcp_close_net(pcp);
00825                             return (NULL);
00826                      }
00827               }
00828        }
00829 
00830        return (setcapabilities(pcp, 1));
00831 }
00832 
00833 static struct PCP *setcapabilities(struct PCPnet *pcp, int dofree)
00834 {
00835        int rc;
00836 
00837        if (docmd(pcp, "CAPABILITY\n", 0))
00838        {
00839               if (dofree)
00840                      pcp_close_net(pcp);
00841               return (NULL);
00842        }
00843 
00844        if ((rc=checkstatus(pcp, NULL)) != 100)
00845        {
00846               if (dofree)
00847                      pcp_close_net(pcp);
00848               return (NULL);
00849        }
00850 
00851        if (!has100(pcp, "PCP1"))
00852        {
00853               if (dofree)
00854                      pcp_close_net(pcp);
00855               return (NULL);
00856        }
00857 
00858        if (!has100(pcp, "ACL"))
00859        {
00860               pcp->pcp.acl_func=NULL;
00861               pcp->pcp.listacl_func=NULL;
00862        }
00863        return ((struct PCP *)pcp);
00864 }
00865 
00866 struct PCP *pcp_find_proxy(const char *username,
00867                         const char *clustername,
00868                         char **errmsg)
00869 {
00870        struct PCPnet *pcp=mkpcp(username);
00871 
00872        if (errmsg)
00873               *errmsg=0;
00874        if (!pcp)
00875               return (NULL);
00876 
00877        if (strchr(username, '\r') || strchr(username, '\n'))
00878        {
00879               errno=EINVAL;
00880               pcp_close_net(pcp);
00881               return (NULL);
00882        }
00883 
00884        if ((pcp->fd=doconnect(pcp, CALENDARDIR "/private", username, NULL,
00885                             clustername,
00886                             errmsg)) < 0)
00887        {
00888               pcp_close_net(pcp);
00889               return (NULL);
00890        }
00891        return ((struct PCP *)pcp);
00892 }
00893 
00894 int pcp_set_proxy(struct PCP *pcp_ptr, const char *proxy)
00895 {
00896        struct PCPnet *pcp=(struct PCPnet *)pcp_ptr;
00897        int rc;
00898        char *p;
00899 
00900        pcp->haserrmsg=0;
00901 
00902        if (strchr(proxy, '\r') || strchr(proxy, '\n'))
00903        {
00904               errno=EINVAL;
00905               return (-1);
00906        }
00907 
00908        p=malloc(strlen(proxy)+sizeof("PROXY \n"));
00909 
00910        if (!p)
00911               return (-1);
00912 
00913        strcat(strcat(strcpy(p, "PROXY "), proxy), "\n");
00914 
00915        if (docmd(pcp, p, 0))
00916        {
00917               free(p);
00918               return (-1);
00919        }
00920 
00921        free(p);
00922        switch ((rc=checkstatus(pcp, NULL)) / 100) {
00923        case 1:
00924        case 2:
00925        case 3:
00926               break;
00927        default:
00928               return (-1);
00929        }
00930 
00931        if (setcapabilities(pcp, 0) == NULL)
00932               return (-1);
00933        return (0);
00934 }
00935 
00936 struct PCP *pcp_reopen_server(const char *username, const char *authtoken,
00937                            char **errmsg)
00938 {
00939        struct PCPnet *pcp=mkpcp(username);
00940        char *authtoken_cpy;
00941        char *p, *q;
00942 
00943        if (!pcp)
00944               return (NULL);
00945 
00946        /* auth token is: sockname/token */
00947 
00948        if ((authtoken_cpy=strdup(authtoken)) == NULL)
00949        {
00950               pcp_close_net(pcp);
00951               return (NULL);
00952        }
00953 
00954        if ((p=strchr(authtoken_cpy, '/')) == NULL)
00955        {
00956               errno=EINVAL;
00957               free(authtoken_cpy);
00958               pcp_close_net(pcp);
00959               return (NULL);
00960        }
00961 
00962        *p++=0;
00963 
00964        for (q=p; *q; ++q)
00965               if (isspace((int)(unsigned char)*q))
00966               {
00967                      errno=EINVAL;
00968                      free(authtoken_cpy);
00969                      pcp_close_net(pcp);
00970                      return (NULL);
00971               }
00972 
00973        if ((pcp->fd=doconnect(pcp, CALENDARDIR "/public", username,
00974                             authtoken_cpy, NULL, errmsg)) < 0)
00975        {
00976               free(authtoken_cpy);
00977               pcp_close_net(pcp);
00978               return (NULL);
00979        }
00980 
00981        if (pcp->authtoken == NULL)
00982        {
00983               char *buf;
00984               int rc;
00985 
00986               buf=malloc(strlen(p)+sizeof("RELOGIN \n"));
00987               if (buf == 0)
00988               {
00989                      free(authtoken_cpy);
00990                      pcp_close_net(pcp);
00991                      return (NULL);
00992               }
00993 
00994               strcat(strcat(strcpy(buf, "RELOGIN "), p), "\n");
00995               free(authtoken_cpy);
00996 
00997               if (docmd(pcp, buf, 0))
00998               {
00999                      free(buf);
01000                      pcp_close_net(pcp);
01001                      return (NULL);
01002               }
01003               free(buf);
01004 
01005               switch ((rc=checkstatus(pcp, NULL)) / 100) {
01006               case 1:
01007               case 2:
01008               case 3:
01009                      break;
01010               default:
01011                      errno=EIO;
01012                      if (errmsg)
01013                      {
01014                             if (*errmsg)
01015                                    free(*errmsg);
01016                             *errmsg=strdup(pcp->readbuf);
01017                      }
01018                      pcp_close_net(pcp);
01019                      return (NULL);
01020               }
01021               if (rc == 102)
01022               {
01023                      if (parseauthtoken(pcp))
01024                      {
01025                             pcp_close_net(pcp);
01026                             return (NULL);
01027                      }
01028               }
01029               else   /* Keeping the same token */
01030                      if ((pcp->authtoken=strdup(authtoken)) == NULL)
01031               {
01032                      pcp_close_net(pcp);
01033                      return (NULL);
01034               }
01035        }
01036        else
01037               free(authtoken_cpy);
01038 
01039        return (setcapabilities(pcp, 1));
01040 }
01041 
01042 static void pcp_close_quit_net(struct PCPnet *pcp)
01043 {
01044        if (pcp->fd >= 0)
01045               docmd(pcp, "QUIT\n", 0);
01046        pcp_close_net(pcp);
01047 }
01048 
01049 static void pcp_close_net(struct PCPnet *pd)
01050 {
01051        if (pd->fd >= 0)
01052               close(pd->fd);
01053        if (pd->sockname)
01054               free(pd->sockname);
01055        if (pd->authtoken)
01056               free(pd->authtoken);
01057        if (pd->readbuf)
01058               free(pd->readbuf);
01059        free(pd->username);
01060        free(pd);
01061 }
01062 
01063 static int cleanup(struct PCPnet *pn)
01064 {
01065        return (0);
01066 }
01067 
01068 static struct PCP_new_eventid *neweventid(struct PCPnet *pn,
01069                                      const char *ev,
01070                                      struct PCP_save_event *se)
01071 {
01072        struct PCPnet_new_eventid *p;
01073        char *q;
01074        char rbuf[BUFSIZ], wbuf[BUFSIZ];
01075        char *rbufptr;
01076        int bufl;
01077        char *wbufptr;
01078        int wbufleft;
01079        char *s;
01080        unsigned new_len, n;
01081 
01082        int seeneol;
01083 
01084        pn->haserrmsg=0;
01085        if (ev && (strchr(ev, '\n') || strchr(ev, '\r')))
01086        {
01087               errno=EINVAL;
01088               return (NULL);
01089        }
01090 
01091        p=malloc(sizeof(struct PCPnet_new_eventid));
01092        if (!p)
01093               return (NULL);
01094        memset(p, 0, sizeof(*p));
01095 
01096        pn->haserrmsg=1;
01097 
01098        if (docmd(pn, "RSET\n", 0))
01099        {
01100               free(p);
01101               return (NULL);
01102        }
01103        switch (checkstatus(pn, NULL) / 100) {
01104        case 1:
01105        case 2:
01106        case 3:
01107               break;
01108        default:
01109               free(p);
01110               return (NULL);
01111        }
01112 
01113        if (docmd(pn, se->flags & PCP_OK_CONFLICT
01114                 ? "CONFLICT ON\n":"CONFLICT OFF\n", 0))
01115        {
01116               free(p);
01117               errno=EINVAL;
01118               return (NULL);
01119        }
01120 
01121        if (docmd(pn, se->flags & PCP_OK_PROXY_ERRORS
01122                 ? "FORCE ON\n":"FORCE OFF\n", 0))
01123        {
01124               free(p);
01125               errno=EINVAL;
01126               return (NULL);
01127        }
01128 
01129        if (ev)
01130        {
01131               pn->haserrmsg=0;
01132               q=malloc(sizeof("DELETE \n")+strlen(ev));
01133               if (!q)
01134               {
01135                      free(p);
01136                      return (NULL);
01137               }
01138               pn->haserrmsg=1;
01139               strcat(strcat(strcpy(q, "DELETE "), ev), "\n");
01140               if (docmd(pn, q, 0))
01141               {
01142                      free(q);
01143                      free(p);
01144                      return (NULL);
01145               }
01146               free(q);
01147 
01148               switch (checkstatus(pn, NULL) / 100) {
01149               case 1:
01150               case 2:
01151               case 3:
01152                      break;
01153               default:
01154                      free(p);
01155                      return (NULL);
01156               }
01157        }
01158 
01159        new_len=30;
01160        for (n=0; n<se->n_event_participants; n++)
01161        {
01162               const char *pp=se->event_participants[n].address;
01163 
01164               if (pp)
01165               {
01166                      if (strchr(pp, '\n') || strchr(pp, '\r'))
01167                      {
01168                             errno=EINVAL;
01169                             free(p);
01170                             return (NULL);
01171                      }
01172 
01173                      new_len += strlen(pp)+1;
01174               }
01175        }
01176 
01177        if ((s=malloc(new_len)) == NULL)
01178        {
01179               free(p);
01180               return (NULL);
01181        }
01182 
01183        strcpy(s, "NEW");
01184 
01185        for (n=0; n<se->n_event_participants; n++)
01186        {
01187               const char *p=se->event_participants[n].address;
01188 
01189               if (p)
01190                      strcat(strcat(s, " "), p);
01191        }
01192 
01193        strcat(s, "\n");
01194 
01195        if (docmd(pn, s, 0))
01196        {
01197               free(s);
01198               free(p);
01199               return (NULL);
01200        }
01201        free(s);
01202 
01203        if ((checkstatus(pn, NULL) / 100) != 3)
01204        {
01205               free(p);
01206               return (NULL);
01207        }
01208 
01209        wbufptr=wbuf;
01210        wbufleft=sizeof(wbuf);
01211        seeneol=1;
01212 
01213        while ((bufl=pcp_read_saveevent(se, rbuf, sizeof(rbuf))) > 0)
01214        {
01215               rbufptr=rbuf;
01216 
01217               while (bufl)
01218               {
01219                      if (seeneol && *rbufptr == '.')
01220                      {
01221                             if (!wbufleft)
01222                             {
01223                                    if (dowrite(pn, wbuf, sizeof(wbuf)))
01224                                           break;
01225                                    wbufptr=wbuf;
01226                                    wbufleft=sizeof(wbuf);
01227                             }
01228                             *wbufptr++='.';
01229                             --wbufleft;
01230                      }
01231 
01232                      if (!wbufleft)
01233                      {
01234                             if (dowrite(pn, wbuf, sizeof(wbuf)))
01235                                    break;
01236                             wbufptr=wbuf;
01237                             wbufleft=sizeof(wbuf);
01238                      }
01239 
01240                      seeneol= *rbufptr == '\n';
01241                      *wbufptr++ = *rbufptr++;
01242                      --wbufleft;
01243                      --bufl;
01244               }
01245        }
01246 
01247        if (bufl)     /* Write error, flush things through */
01248        {
01249               if (bufl > 0)
01250                      while ((bufl=pcp_read_saveevent(se, rbuf,
01251                                                  sizeof(rbuf))) > 0)
01252                             ;
01253               free(p);
01254               return (NULL);
01255        }
01256 
01257        s=seeneol ? ".\n":"\n.\n";
01258 
01259        while (*s)
01260        {
01261               if (!wbufleft)
01262               {
01263                      if (dowrite(pn, wbuf, sizeof(wbuf)))
01264                      {
01265                             free(p);
01266                             return (NULL);
01267                      }
01268                      wbufptr=wbuf;
01269                      wbufleft=sizeof(wbuf);
01270               }
01271               *wbufptr++= *s++;
01272               --wbufleft;
01273        }
01274 
01275        if (wbufptr > wbuf && dowrite(pn, wbuf, wbufptr-wbuf))
01276        {
01277               free(p);
01278               return (NULL);
01279        }
01280 
01281        if (getfullreply(pn))
01282        {
01283               free(p);
01284               return (NULL);
01285        }
01286 
01287        if (checkstatus(pn, NULL) != 109)
01288        {
01289               errno=EIO;
01290               free(p);
01291               return (NULL);
01292        }
01293 
01294        s=pn->readbuf;
01295 
01296        getword(pn, &s);     /* Skip 109 */
01297 
01298        q=getword(pn, &s);
01299        if (!q)
01300        {
01301               errno=EIO;
01302               free(p);
01303               return (NULL);
01304        }
01305        if ((p->eventid.eventid=strdup(q)) == NULL)
01306        {
01307               free(p);
01308               return (NULL);
01309        }
01310        return (&p->eventid);
01311 }
01312 
01313 static void destroyeventid(struct PCPnet *pn, struct PCPnet_new_eventid *id)
01314 {
01315        free(id->eventid.eventid);
01316        free(id);
01317 }
01318 
01319 static int docommitevent2(struct PCPnet *pn, int *,
01320                        void (*)(const char *, const char *, void *),
01321                        void *);
01322 
01323 static int commitevent(struct PCPnet *pn, struct PCPnet_new_eventid *id,
01324                      struct PCP_commit *ci)
01325 {
01326        if (!id->isbooked)
01327        {
01328               int rc=bookevent(pn, id, ci);
01329 
01330               if (rc)
01331                      return (rc);
01332        }
01333 
01334        return (docommitevent2(pn, &ci->errcode, ci->proxy_callback,
01335                             ci->proxy_callback_ptr));
01336 }
01337 
01338 static int docommitevent2(struct PCPnet *pn, int *errcode,
01339                        void (*proxy_callback)(const char *,
01340                                            const char *,
01341                                            void *),
01342                        void *proxy_callback_ptr)
01343 {
01344        int s;
01345 
01346        pn->haserrmsg=0;
01347 
01348        if (dowrite(pn, "COMMIT\n", 0))
01349               return (-1);
01350 
01351        pn->haserrmsg=1;
01352 
01353        while ((s=getonelinereply(pn)) >= 0)
01354        {
01355               int n=checkstatus(pn, errcode);
01356 
01357               if (n == 111)
01358               {
01359                      char *p=pn->readbuf+3;
01360                      char *action;
01361 
01362                      if (*p)
01363                             ++p;
01364 
01365 
01366                      action=getword(pn, &p);
01367 
01368                      while (*p && isspace((int)(unsigned char)*p))
01369                             ++p;
01370 
01371                      if (proxy_callback)
01372                             (*proxy_callback)(action, p,
01373                                             proxy_callback_ptr);
01374               }
01375 
01376               if (s > 0)
01377                      return ( (n / 100) < 4 ? 0:-1);
01378        }
01379        pn->haserrmsg=0;
01380        return (-1);
01381 }
01382 
01383 static int docommitresponse(struct PCPnet *,
01384                          int (*)(const char *, time_t, time_t,
01385                                 const char *, void *),
01386                          void *,
01387                          int *);
01388 
01389 static int bookevent(struct PCPnet *pn, struct PCPnet_new_eventid *id,
01390                    struct PCP_commit *ci)
01391 {
01392        char *q;
01393        unsigned i;
01394        int ss;
01395 
01396        ci->errcode=0;
01397        pn->haserrmsg=0;
01398 
01399        if (ci->n_event_times <= 0)
01400        {
01401               errno=EINVAL;
01402               return (-1);
01403        }
01404 
01405        pn->haserrmsg=1;
01406 
01407        switch (checkstatus(pn, NULL) / 100) {
01408        case 1:
01409        case 2:
01410        case 3:
01411               break;
01412        default:
01413               return (-1);
01414        }
01415 
01416        /* yyyymmddhhmmss - 14 chars.  Each time is <space>start-end */
01417 
01418        pn->haserrmsg=0;
01419 
01420        q=malloc(ci->n_event_times * 32 + 20);    /* Eh, that's enough */
01421 
01422        if (!q)
01423               return (-1);
01424 
01425        strcpy(q, "BOOK");
01426 
01427        for (i=0; i<ci->n_event_times; i++)
01428        {
01429               char buf[15];
01430 
01431               pcp_gmtimestr(ci->event_times[i].start, buf);
01432               strcat(strcat(q, " "), buf);
01433               pcp_gmtimestr(ci->event_times[i].end, buf);
01434               strcat(strcat(q, "-"), buf);
01435        }
01436        strcat(q, "\n");
01437 
01438        if (dowrite(pn, q, 0))
01439        {
01440               free(q);
01441               return (-1);
01442        }
01443        free(q);
01444 
01445        ss=docommitresponse(pn, ci->add_conflict_callback,
01446                          ci->add_conflict_callback_ptr,
01447                          &ci->errcode);
01448 
01449        if (ss == 0)
01450               id->isbooked=1;
01451        return (ss);
01452 }
01453 
01454 static int docommitresponse(struct PCPnet *pn,
01455                          int (*conflict_func)(const char *, time_t, time_t,
01456                                            const char *, void *),
01457                          void *callback_arg,
01458                          int *errcode)
01459 {
01460        int s;
01461        int rc=0;
01462 
01463        pn->haserrmsg=0;
01464 
01465        while ((s=getonelinereply(pn)) >= 0)
01466        {
01467               int ss=checkstatus(pn, errcode);
01468 
01469               switch (ss / 100) {
01470               case 1:
01471               case 2:
01472               case 3:
01473                      break;
01474               default:
01475                      if (ss == 403)
01476                      {
01477                             char eventid[EVENTID_MAXLEN];
01478                             char from[15];
01479                             char to[15];
01480                             char addr[ADDR_MAXLEN];
01481                             char dummy;
01482                             time_t from_t, to_t;
01483 
01484                             if (sscanf(pn->readbuf,
01485                                       "403%c" ADDR_SSCANF " %14s %14s "
01486                                       EVENTID_SSCANF,
01487                                       &dummy,
01488                                       addr, from, to,
01489                                       eventid)
01490                                 != 5)
01491                             {
01492                                    rc= -1;
01493                                    return (-1);
01494                             }
01495 
01496                             from_t=pcp_gmtime_s(from);
01497                             to_t=pcp_gmtime_s(to);
01498                             if (!from_t || !to_t)
01499                             {
01500                                    errno=EIO;
01501                                    return (-1);
01502                             }
01503 
01504                             if (rc == 0 && conflict_func)
01505                                    rc= (*conflict_func)
01506                                           (eventid, from_t, to_t, addr,
01507                                            callback_arg);
01508                             if (errcode)
01509                                    *errcode=PCP_ERR_CONFLICT;
01510                      }
01511                      rc= -1;
01512               }
01513               pn->haserrmsg=1;
01514               if (s > 0)
01515                      break;
01516               pn->haserrmsg=0;
01517        }
01518 
01519        return (rc);
01520 }
01521 
01522 static int parse105(struct PCPnet *pn, time_t *from_t, time_t *to_t,
01523                   char eventid[EVENTID_MAXLEN])
01524 {
01525        char dummy;
01526        char from[15];
01527        char to[15];
01528 
01529        if (sscanf(pn->readbuf, "105%c" EVENTID_SSCANF " %14s %14s",
01530                  &dummy, eventid, from, to) == 4)
01531        {
01532               if ((*from_t=pcp_gmtime_s(from)) &&
01533                   (*to_t=pcp_gmtime_s(to)))
01534                      return (0);
01535        }
01536        errno=EIO;
01537        return (-1);
01538 }
01539 
01540 static int listallevents(struct PCPnet *pn, struct PCP_list_all *la)
01541 {
01542        char cmdbuf[100];
01543        int rc, s;
01544 
01545        strcpy(cmdbuf, "LIST");
01546 
01547        if (la->list_from || la->list_to)
01548        {
01549               char buf[15];
01550 
01551               strcat(cmdbuf, " FROM ");
01552               if (la->list_from)
01553               {
01554                      pcp_gmtimestr(la->list_from, buf);
01555                      strcat(cmdbuf, buf);
01556               }
01557               strcat(cmdbuf, "-");
01558               if (la->list_to)
01559               {
01560                      pcp_gmtimestr(la->list_to, buf);
01561                      strcat(cmdbuf, buf);
01562               }
01563        }
01564 
01565        strcat(cmdbuf, "\n");
01566 
01567        pn->haserrmsg=0;
01568        if (dowrite(pn, cmdbuf, 0) < 0)
01569               return (-1);
01570 
01571        rc=0;
01572        pn->haserrmsg=1;
01573 
01574        while ((s=getonelinereply(pn)) >= 0)
01575        {
01576               int n=checkstatus(pn, NULL);
01577               if (n >= 400)
01578                      rc= -1;
01579               if (n == 105)
01580               {
01581                      char eventid[EVENTID_MAXLEN];
01582 
01583                      if (parse105(pn, &la->event_from, &la->event_to,
01584                                  eventid) == 0)
01585                      {
01586                             la->event_id=eventid;
01587                             if (rc == 0)
01588                                    rc= (*la->callback_func)
01589                                           (la, la->callback_arg);
01590                      }
01591               }
01592               if (s > 0)
01593                      break;
01594        }
01595 
01596        if (s < 0)
01597        {
01598               pn->haserrmsg=0;
01599               rc= -1;
01600        }
01601        return (rc);
01602 }
01603 
01604 static int cancelevent(struct PCPnet *pn, const char *id, int *errcode)
01605 {
01606        char *buf;
01607 
01608        if (errcode)
01609               *errcode=0;
01610 
01611        pn->haserrmsg=0;
01612 
01613        if (strchr(id, '\r') || strchr(id, '\n'))
01614        {
01615               errno=EINVAL;
01616               return (-1);
01617        }
01618 
01619        buf=malloc(strlen(id)+20);
01620        if (!buf)
01621               return (-1);
01622 
01623        strcat(strcat(strcpy(buf, "CANCEL "), id), "\n");
01624        if (docmd(pn, buf, 0))
01625        {
01626               free(buf);
01627               return (-1);
01628        }
01629        pn->haserrmsg=1;
01630 
01631        switch (checkstatus(pn, errcode) / 100) {
01632        case 1:
01633        case 2:
01634        case 3:
01635               break;
01636        default:
01637               return (-1);
01638        }
01639        return (0);
01640 }
01641 
01642 static int uncancelevent(struct PCPnet *pn, const char *id,
01643                       int flags, struct PCP_uncancel *ui)
01644 {
01645        char *buf;
01646 
01647        pn->haserrmsg=0;
01648        if (ui)
01649               ui->errcode=0;
01650 
01651        if (strchr(id, '\r') || strchr(id, '\n'))
01652        {
01653               errno=EINVAL;
01654               return (-1);
01655        }
01656        if (docmd(pn, "RSET\n", 0))
01657               return (-1);
01658        pn->haserrmsg=1;
01659 
01660        switch (checkstatus(pn, NULL) / 100) {
01661        case 1:
01662        case 2:
01663        case 3:
01664               break;
01665        default:
01666               return (-1);
01667        }
01668 
01669        pn->haserrmsg=0;
01670        if (docmd(pn, flags & PCP_OK_CONFLICT
01671                 ? "CONFLICT ON\n":"CONFLICT OFF\n", 0))
01672        {
01673               return (-1);
01674        }
01675        if (docmd(pn, flags & PCP_OK_PROXY_ERRORS
01676                 ? "FORCE ON\n":"FORCE OFF\n", 0))
01677        {
01678               return (-1);
01679        }
01680 
01681        pn->haserrmsg=1;
01682 
01683        switch (checkstatus(pn, NULL) / 100) {
01684        case 1:
01685        case 2:
01686        case 3:
01687               break;
01688        default:
01689               return (-1);
01690        }
01691 
01692        buf=malloc(strlen(id)+20);
01693        if (!buf)
01694               return (-1);
01695 
01696        strcat(strcat(strcpy(buf, "UNCANCEL "), id), "\n");
01697        if (dowrite(pn, buf, 0))
01698        {
01699               free(buf);
01700               return (-1);
01701        }
01702 
01703        return (docommitresponse(pn, ui ? ui->uncancel_conflict_callback:NULL,
01704                              ui ? ui->uncancel_conflict_callback_ptr:NULL,
01705                              ui ? &ui->errcode:NULL));
01706 }
01707 
01708 static int deleteevent(struct PCPnet *pn,
01709                      struct PCP_delete *del)
01710 {
01711        char *buf;
01712 
01713        pn->haserrmsg=0;
01714        del->errcode=0;
01715 
01716        if (strchr(del->id, '\r') || strchr(del->id, '\n'))
01717        {
01718               errno=EINVAL;
01719               return (-1);
01720        }
01721        if (docmd(pn, "RSET\n", 0))
01722               return (-1);
01723        pn->haserrmsg=1;
01724 
01725        switch (checkstatus(pn, NULL) / 100) {
01726        case 1:
01727        case 2:
01728        case 3:
01729               break;
01730        default:
01731               return (-1);
01732        }
01733        pn->haserrmsg=0;
01734 
01735        buf=malloc(strlen(del->id)+20);
01736        if (!buf)
01737               return (-1);
01738 
01739        strcat(strcat(strcpy(buf, "DELETE "), del->id), "\n");
01740        if (docmd(pn, buf, 0))
01741        {
01742               free(buf);
01743               return (-1);
01744        }
01745 
01746        pn->haserrmsg=1;
01747 
01748        switch (checkstatus(pn, &del->errcode) / 100) {
01749        case 1:
01750        case 2:
01751        case 3:
01752               break;
01753        default:
01754               return (-1);
01755        }
01756 
01757        return (docommitevent2(pn, &del->errcode,
01758                             del->proxy_callback,
01759                             del->proxy_callback_ptr));
01760 }
01761 
01762 static int retr_105(struct PCPnet *, struct PCP_retr *);
01763 static int retr_106(struct PCPnet *, struct PCP_retr *);
01764 static int retr_110(struct PCPnet *, struct PCP_retr *);
01765 static int retr_107(struct PCPnet *, struct PCP_retr *, int);
01766 
01767 static int retrevent(struct PCPnet *pn, struct PCP_retr *ri)
01768 {
01769        char items_buf[256];
01770        unsigned i;
01771        size_t cnt;
01772        char *q;
01773        int errflag;
01774 
01775        items_buf[0]=0;
01776        pn->haserrmsg=0;
01777 
01778        if (ri->callback_retr_status)
01779               strcat(items_buf, " STATUS");
01780        if (ri->callback_retr_date)
01781               strcat(items_buf, " DATE");
01782        if (ri->callback_retr_participants)
01783               strcat(items_buf, " ADDR");
01784        if (ri->callback_rfc822_func)
01785               strcat(items_buf, " TEXT");
01786        else if (ri->callback_headers_func)
01787               strcat(items_buf, " HEADERS");
01788 
01789        if (items_buf[0] == 0)
01790        {
01791               errno=EIO;
01792               return (-1);
01793        }
01794 
01795        cnt=strlen(items_buf)+256;
01796 
01797        for (i=0; ri->event_id_list[i]; i++)
01798        {
01799               const char *p=ri->event_id_list[i];
01800 
01801               if (strchr(p, '\n'))
01802               {
01803                      errno=EIO;
01804                      return (-1);
01805               }
01806               cnt += 1 + strlen(p);
01807        }
01808 
01809        q=malloc(cnt);
01810 
01811        if (!q)
01812               return (-1);
01813 
01814        strcat(strcat(strcpy(q, "RETR"), items_buf), " EVENTS");
01815 
01816        for (i=0; ri->event_id_list[i]; i++)
01817        {
01818               strcat(strcat(q, " "), ri->event_id_list[i]);
01819        }
01820        strcat(q, "\n");
01821 
01822        if (dowrite(pn, q, 0) < 0)
01823        {
01824               free(q);
01825               return (-1);
01826        }
01827        free(q);
01828 
01829        errflag=0;
01830 
01831        for (;;)
01832        {
01833               int rc;
01834 
01835               if (!errflag)
01836                      pn->haserrmsg=0;
01837               if (getfullreply(pn) < 0)
01838                      return (-1);
01839 
01840               if (!errflag)
01841                      pn->haserrmsg=1;
01842               rc=checkstatus(pn, NULL);
01843 
01844               if ( rc < 100 || rc >= 400)
01845                      return (-1);
01846               if (rc == 108)
01847                      break;
01848               pn->haserrmsg=0;
01849 
01850               switch (rc) {
01851               case 105:
01852                      if (errflag)
01853                             break;
01854                      rc=retr_105(pn, ri);
01855                      if (rc)
01856                             errflag=rc;
01857                      break;
01858               case 106:
01859                      if (errflag)
01860                             break;
01861                      rc=retr_106(pn, ri);
01862                      if (rc)
01863                             errflag=rc;
01864                      break;
01865               case 110:
01866                      if (errflag)
01867                             break;
01868                      rc=retr_110(pn, ri);
01869                      if (rc)
01870                             errflag=rc;
01871                      break;
01872               case 107:
01873                      rc=retr_107(pn, ri, errflag);
01874                      if (!errflag && rc)
01875                             errflag=rc;
01876                      break;
01877               default:
01878                      close(pn->fd);
01879                      pn->fd= -1;
01880                      errno=EIO;
01881                      return (-1);
01882               }
01883        }
01884 
01885        return (errflag);
01886 }
01887 
01888 static int retr_105(struct PCPnet *pn, struct PCP_retr *ri)
01889 {
01890        char eventid[EVENTID_MAXLEN];
01891        time_t from_t, to_t;
01892 
01893        if (parse105(pn, &from_t, &to_t, eventid) == 0)
01894        {
01895               ri->event_id=eventid;
01896 
01897               if (ri->callback_retr_date)
01898                      return ( (*ri->callback_retr_date)
01899                              (ri, from_t, to_t, ri->callback_arg));
01900        }
01901 
01902        return (0);
01903 }
01904 
01905 static int retr_106(struct PCPnet *pn, struct PCP_retr *ri)
01906 {
01907        char dummy;
01908        char eventid[EVENTID_MAXLEN];
01909        char addr[ADDR_MAXLEN];
01910 
01911        if (sscanf(pn->readbuf, "106%c" EVENTID_SSCANF " " ADDR_SSCANF,
01912                  &dummy, eventid, addr) == 3)
01913        {
01914               ri->event_id=eventid;
01915 
01916               if (ri->callback_retr_participants)
01917                      return ( (*ri->callback_retr_participants)
01918                              (ri, addr, NULL, ri->callback_arg));
01919        }
01920 
01921        return (0);
01922 }
01923 
01924 static int retr_110(struct PCPnet *pn, struct PCP_retr *ri)
01925 {
01926        char dummy;
01927        char eventid[EVENTID_MAXLEN];
01928 
01929        if (sscanf(pn->readbuf, "110%c" EVENTID_SSCANF, 
01930                  &dummy, eventid) == 2)
01931        {
01932               const char *p, *q;
01933               char *r, *s;
01934               int flags=0;
01935 
01936               ri->event_id=eventid;
01937 
01938               p=pn->readbuf+4;
01939               while (p)
01940               {
01941                      if (isspace((int)(unsigned char)*p))
01942                             break;
01943                      ++p;
01944               }
01945 
01946               while (p)
01947               {
01948                      if (!isspace((int)(unsigned char)*p))
01949                             break;
01950                      ++p;
01951               }
01952 
01953               for (q=p; *q; q++)
01954               {
01955                      if (isspace((int)(unsigned char)*q))
01956                             break;
01957               }
01958               r=malloc(q-p+1);
01959               if (!r)
01960               {
01961                      pn->haserrmsg=0;
01962                      return (-1);
01963               }
01964               memcpy(r, p, q-p);
01965               r[q-p]=0;
01966 
01967               for (s=r; (s=strtok(s, ",")) != 0; s=0)
01968               {
01969                      if (strcasecmp(s, "CANCELLED") == 0)
01970                             flags |= LIST_CANCELLED;
01971                      else if (strcasecmp(s, "BOOKED") == 0)
01972                             flags |= LIST_BOOKED;
01973                      else if (strcasecmp(s, "PROXY") == 0)
01974                             flags |= LIST_PROXY;
01975               }
01976 
01977 
01978               if (ri->callback_retr_status)
01979                      return ( (*ri->callback_retr_status)
01980                              (ri, flags, ri->callback_arg));
01981        }
01982 
01983        return (0);
01984 }
01985 
01986 static int retr_107(struct PCPnet *pn, struct PCP_retr *ri, int ignore)
01987 {
01988        char dummy;
01989        char eventid[EVENTID_MAXLEN];
01990        int rc=0;
01991        int ch;
01992        int seeneol;
01993        int seendot;
01994        size_t nn;
01995 
01996        if (sscanf(pn->readbuf, "107%c" EVENTID_SSCANF,
01997                  &dummy, eventid) != 2)
01998        {
01999               errno=EIO;
02000               rc= -1;
02001        }
02002 
02003        ri->event_id=eventid;
02004 
02005        if (rc == 0 && ri->callback_begin_func)
02006               rc= (*ri->callback_begin_func)(ri, ri->callback_arg);
02007 
02008        seeneol=1;
02009        seendot=1;
02010        nn=0;
02011 
02012        ch=EOF;
02013        for (;;)
02014        {
02015               if (ch == EOF)
02016                      ch=readch(pn, nn);
02017               if (ch == EOF)
02018               {
02019                      rc= -1;
02020                      break;
02021               }
02022               if (ch == '\r')
02023                      continue;
02024 
02025               if (seeneol)
02026                      seendot= ch == '.';
02027               else
02028               {
02029                      if ( ch == '\n' && seendot)
02030                             break;
02031                      seendot=0;
02032               }
02033               seeneol= ch == '\n';
02034 
02035               if (!seendot)
02036                      pn->readbuf[nn++]=ch;
02037               ch=EOF;
02038 
02039               if (ri->callback_rfc822_func)
02040               {
02041                      if (nn >= 8192)
02042                      {
02043                             if (rc == 0)
02044                                    rc= (*ri->callback_rfc822_func)
02045                                           (ri, pn->readbuf, nn,
02046                                            ri->callback_arg);
02047                             nn=0;
02048                      }
02049               }
02050               else if (ri->callback_headers_func)
02051               {
02052                      if (nn > 8192)
02053                             nn=8192;      /* Trim excessive hdrs */
02054 
02055                      if (seeneol)
02056                      {
02057                             char *h;
02058                             char *v;
02059 
02060                             ch=readch(pn, nn);
02061                             if (ch == EOF)
02062                             {
02063                                    rc= -1;
02064                                    break;
02065                             }
02066 
02067                             if (ch != '\n' && isspace(ch))
02068                             {
02069                                    /* Header wrapped */
02070 
02071                                    while (ch != EOF && ch != '\n'
02072                                           && isspace(ch))
02073                                           ch=readch(pn, nn);
02074                                    pn->readbuf[nn-1]=' ';
02075                                    continue;
02076                             }
02077                             pn->readbuf[nn-1]=0;
02078                             h=pn->readbuf;
02079                             if ((v=strchr(h, ':')) == NULL)
02080                                    v="";
02081                             else
02082                             {
02083                                    *v++=0;
02084                                    while (*v &&
02085                                           isspace((int)(unsigned char)*v))
02086                                           ++v;
02087                             }
02088                             if (rc == 0)
02089                                    rc=(*ri->callback_headers_func)
02090                                           (ri, h, v, ri->callback_arg);
02091                             nn=0;
02092                      }
02093               }
02094               else nn=0;
02095        }
02096 
02097        if (ri->callback_rfc822_func)
02098        {
02099               if (rc == 0)
02100                      rc= (*ri->callback_rfc822_func)
02101                             (ri, pn->readbuf, nn, ri->callback_arg);
02102        }
02103 
02104        if (rc == 0 && ri->callback_end_func)
02105               rc= (*ri->callback_end_func)(ri, ri->callback_arg);
02106        return (rc);
02107 }
02108 
02109 
02110 static int setacl(struct PCPnet *pn, const char *who, int flags)
02111 {
02112        char buf[1024];
02113 
02114        pn->haserrmsg=0;
02115        if (strchr(who, '\r') || strchr(who, '\n') || strlen(who) > 512)
02116        {
02117               errno=EINVAL;
02118               return (-1);
02119        }
02120 
02121        sprintf(buf, "ACL SET %s", who);
02122        pcp_acl_name(flags, buf);
02123        strcat(buf, "\n");
02124 
02125        if (docmd(pn, buf, 0))
02126               return (-1);
02127        pn->haserrmsg=1;
02128        switch (checkstatus(pn, NULL) / 100) {
02129        case 1:
02130        case 2:
02131        case 3:
02132               break;
02133        default:
02134               errno=EIO;
02135               return (-1);
02136        }
02137        return (0);
02138 }
02139 
02140 
02141 static int listacl(struct PCPnet *pn, int (*func)(const char *, int, void *),
02142                  void *arg)
02143 {
02144        int rc;
02145        int s;
02146 
02147        pn->haserrmsg=0;
02148        if (dowrite(pn, "ACL LIST\n", 0) < 0)
02149               return (-1);
02150 
02151        rc=0;
02152        pn->haserrmsg=1;
02153 
02154        while ((s=getonelinereply(pn)) >= 0)
02155        {
02156               int n=checkstatus(pn, NULL);
02157               if (n >= 400)
02158                      rc= -1;
02159               if (n == 103)
02160               {
02161                      char addr[ADDR_MAXLEN];
02162                      char dummy;
02163 
02164                      if (sscanf(pn->readbuf, "103%c" ADDR_SSCANF,
02165                                &dummy, addr) == 2)
02166                      {
02167                             const char *p=pn->readbuf+4;
02168                             int flags=0;
02169 
02170                             for ( ; *p; p++)
02171                                    if (isspace((int)(unsigned char)*p))
02172                                           break;
02173 
02174                             while (*p)
02175                             {
02176                                    const char *q;
02177                                    char buf[256];
02178 
02179                                    if (isspace((int)(unsigned char)*p))
02180                                    {
02181                                           ++p;
02182                                           continue;
02183                                    }
02184                                    q=p;
02185 
02186                                    for ( ; *p; p++)
02187                                           if (isspace((int)
02188                                                      (unsigned char)*p))
02189                                                  break;
02190                                    buf[0]=0;
02191                                    strncat(buf, q, p-q < 255 ? p-q:255);
02192 
02193                                    flags |= pcp_acl_num(buf);
02194                             }
02195 
02196                             if (rc == 0)
02197                                    rc= (*func)(addr, flags, arg);
02198                      }
02199                      else
02200                      {
02201                             if (rc == 0)
02202                             {
02203                                    rc= -1;
02204                                    errno=EIO;
02205                             }
02206                      }
02207               }
02208               if (s > 0)
02209                      break;
02210        }
02211 
02212        if (s < 0)
02213        {
02214               pn->haserrmsg=0;
02215               rc= -1;
02216        }
02217        return (rc);
02218 }
02219 
02220 static void noop(struct PCPnet *pd)
02221 {
02222        docmd(pd, "NOOP\n", 0);
02223 }