Back to index

courier  0.68.2
pcp.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 2001-2010 Double Precision, Inc.  See COPYING for
00003 ** distribution information.
00004 */
00005 
00006 
00007 /*
00008 */
00009 #include      "sqwebmail.h"
00010 #include      "pcp.h"
00011 #include      "pref.h"
00012 #include      "htmllibdir.h"
00013 #include      "sqconfig.h"
00014 #include      "auth.h"
00015 #include      "addressbook.h"
00016 #include      "pcp/pcp.h"
00017 #include      "cgi/cgi.h"
00018 #include      "rfc822/rfc822.h"
00019 #include      "rfc822/rfc822hdr.h"
00020 #include      "rfc822/rfc2047.h"
00021 #include      "maildir/maildircreate.h"
00022 #include      "maildir/maildirmisc.h"
00023 #include      "maildir/maildirquota.h"
00024 #include      "maildir/maildirgetquota.h"
00025 #include      "numlib/numlib.h"
00026 #include      "maildir.h"
00027 #include      "newmsg.h"
00028 #include      "pref.h"
00029 #include      "courierauth.h"
00030 #include      <stdio.h>
00031 #include      <string.h>
00032 #include      <stdlib.h>
00033 #include      <signal.h>
00034 #include      <ctype.h>
00035 #include      <unistd.h>
00036 #include      <errno.h>
00037 #include      <sys/types.h>
00038 #include      <sys/stat.h>
00039 #if HAVE_SYS_WAIT_H
00040 #include      <sys/wait.h>
00041 #endif
00042 #if HAVE_FCNTL_H
00043 #include      <fcntl.h>
00044 #endif
00045 
00046 #ifndef WEXITSTATUS
00047 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
00048 #endif
00049 #ifndef WIFEXITED
00050 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
00051 #endif
00052 
00053 #define              CACHE  "calendar.cache"
00054 #define              TOKEN  "calendar.authtoken"
00055 
00056 #define              CHANGEDFILE "calendar/changed"     /* Hack */
00057 
00058 #include      "strftime.h"
00059 
00060 extern FILE *open_langform(const char *lang, const char *formname,
00061                         int print_header);
00062 
00063 extern const char *myhostname();
00064 extern void output_attrencoded_oknl_fp(const char *, FILE *);
00065 extern void output_scriptptrget();
00066 extern void output_attrencoded(const char *);
00067 extern void print_safe(const char *);
00068 extern const char *sqwebmail_content_charset;
00069 extern const char *sqwebmail_content_language;
00070 extern void output_form(const char *);
00071 extern void newmsg_preview(const char *);
00072 extern void output_urlencoded(const char *);
00073 extern void attachments_head(const char *, const char *, const char *);
00074 extern char *newmsg_createsentmsg(const char *, int *);
00075 extern const char *sqwebmail_mailboxid;
00076 extern char *scriptptrget();
00077 extern void attach_delete(const char *);
00078 extern int attach_upload(const char *,
00079                       const char *,
00080                       const char *);
00081 
00082 extern void newmsg_showfp(FILE *, int *);
00083 
00084 static struct PCP *calendar=NULL;
00085 static void refreshcache(struct PCP *);
00086 extern size_t get_timeoutsoft();
00087 
00088 
00089 /*
00090 ** CGI process startup
00091 */
00092 
00093 void sqpcp_init()
00094 {
00095        calendar=NULL;
00096 }
00097 
00098 /*
00099 ** CGI process shutdown
00100 */
00101 
00102 void sqpcp_close()
00103 {
00104        if (calendar)
00105        {
00106               pcp_close(calendar);
00107               calendar=NULL;
00108        }
00109 }
00110 
00111 static int checked_calendar_mode=0;
00112 static char calendar_mode[24];
00113 
00114 static const char *sqpcp_mode()
00115 {
00116        if (!checked_calendar_mode)
00117        {
00118               FILE *f;
00119               char *p;
00120 
00121               calendar_mode[0]=0;
00122 
00123               f=fopen(CALENDARMODE, "r");
00124 
00125               if (f)
00126               {
00127                      if (fgets(calendar_mode, sizeof(calendar_mode),
00128                               f) == NULL)
00129                      {
00130                             calendar_mode[0]=0;
00131                      }
00132                      fclose(f);
00133               }
00134 
00135               if ((p=strchr(calendar_mode, '\n')) != 0)
00136                      *p=0;
00137               checked_calendar_mode=1;
00138        }
00139 
00140        return (calendar_mode[0] ? calendar_mode:NULL);
00141 }
00142 
00143 /*
00144 ** Log in to calendar.
00145 */
00146 
00147 static void do_pcplogin(const char *userid, const char *password, int showerr);
00148 
00149 void sqpcp_login(const char *userid, const char *password)
00150 {
00151        do_pcplogin(userid, password, 0);
00152 }
00153 
00154 static void do_pcplogin(const char *userid, const char *password, int showerr)
00155 {
00156        struct PCP *pcp;
00157 
00158        unlink(TOKEN);
00159        unlink(CACHE);       /* Rebuild it later*/
00160 
00161        if (!sqpcp_mode())
00162               return;
00163 
00164        mkdir("calendar", 0700);
00165 
00166        if (sqpcp_has_groupware())  /* Groupware mode, login to server */
00167        {
00168               char *errflag=0;
00169 
00170               pcp=pcp_open_server(userid, password, &errflag);
00171 
00172               if (!pcp && errflag && showerr)
00173               {
00174                      printf("%s<div class=\"indent\"><pre class=\"small-error\">",
00175                             getarg("CALENDARLOGINERR"));
00176                      output_attrencoded_oknl_fp(errflag, stdout);
00177                      printf("</pre></div>\n");
00178               }
00179               if (errflag)
00180                      free(errflag);
00181        }
00182        else
00183        {
00184               pcp=sqpcp_calendar();
00185        }
00186 
00187        if (pcp)
00188        {
00189               const char *p=pcp_authtoken(pcp);
00190 
00191               if (p)
00192               {
00193                      FILE *f;
00194                      int u=umask(077);
00195 
00196                      f=fopen(TOKEN, "w");
00197                      umask(u);
00198                      if (f)
00199                      {
00200                             fprintf(f, "%s\n", p);
00201                             fclose(f);
00202                      }
00203               }
00204               pcp_cleanup(pcp);
00205               refreshcache(pcp);
00206        }
00207 }
00208 
00209 /*
00210 ** Format of the CACHE file:
00211 **
00212 **  start<TAB>end<TAB>eventid<TAB>flags<TAB>subject
00213 */
00214 
00215 struct cacherecord {
00216        time_t start, end;
00217        char *eventid;
00218        char *flags;
00219        char *subject;
00220 } ;
00221 
00222 int sqpcp_has_calendar()
00223 {
00224        return (sqpcp_mode() ? 1:0);
00225 }
00226 
00227 int sqpcp_has_groupware()
00228 {
00229        const char *p=sqpcp_mode();
00230 
00231        return (p && strcmp(p, "net") == 0);
00232 }
00233 
00234 static int createcache(struct PCP *,
00235                      struct cacherecord **, unsigned *, time_t, time_t);
00236 static void destroycache(struct cacherecord *, unsigned);
00237 
00238 /*
00239 ** Are we logged in?  If so, refresh the calendar event cache that we
00240 ** display on the main folders screen, if it is stale.
00241 */
00242 
00243 static int need_refresh();
00244 
00245 int sqpcp_loggedin()
00246 {
00247        struct PCP *pcp;
00248 
00249        if (!sqpcp_mode())
00250               return (0);
00251 
00252        if (sqpcp_has_groupware())
00253        {
00254               struct stat stat_buf;
00255 
00256               if (stat(TOKEN, &stat_buf))
00257                      return (0);   /* Login session dropped */
00258        }
00259 
00260        if (!need_refresh())
00261               return (1);
00262        pcp=sqpcp_calendar();
00263        if (pcp)
00264               refreshcache(pcp);
00265        return (1);
00266 }
00267 
00268 /* Check if it's time to rebuild CACHE file */
00269 
00270 static const char *parsetimet(const char *buf, time_t *tp)
00271 {
00272        *tp=libmail_strtotime_t(&buf);
00273 
00274        if (*buf == '\t')
00275               ++buf;
00276        return buf;
00277 }
00278 
00279 static int need_refresh()
00280 {
00281        FILE *fp;
00282        struct stat stat_buf;
00283 
00284        /* Check whether it's time to rebuild the cache */
00285 
00286        fp=fopen(CACHE, "r");
00287 
00288        if (stat(CHANGEDFILE, &stat_buf) == 0)
00289        {
00290               if (fp)
00291                      fclose(fp);
00292               return (1);
00293        }
00294 
00295        if (fp)
00296        {
00297               struct stat stat_buf;
00298 
00299               char buffer[BUFSIZ];
00300               const char *p;
00301 
00302               time_t a, b;
00303 
00304               int ch=getc(fp);
00305 
00306               if (ch == EOF)
00307               {
00308                      fclose(fp);
00309                      return (0); /* No events scheduled */
00310               }
00311 
00312               ungetc(ch, fp);
00313               if (fgets(buffer, sizeof(buffer), fp) &&
00314                   (p=parsetimet(buffer, &a)) &&
00315                   parsetimet(p, &b))
00316               {
00317                      time_t now;
00318 
00319                      time(&now);
00320 
00321                      if (now < b)  /* Event expired */
00322                      {
00323                             if (fstat(fileno(fp), &stat_buf) == 0)
00324                             {
00325                                    /*
00326                                    ** Check in every TIMEOUTSOFT/2 in
00327                                    ** any case.
00328                                    */
00329 
00330                                    if (stat_buf.st_mtime >
00331                                        now - get_timeoutsoft()/2)
00332                                    {
00333                                           fclose(fp);   /* Not yet */
00334                                           return (0);
00335                                    }
00336                             }
00337                      }
00338               }
00339               fclose(fp);
00340               unlink(CACHE);
00341               return (1);
00342        }
00343        return (0);
00344 }
00345 
00346 static void refreshcache(struct PCP *pcp)
00347 {
00348        struct cacherecord *recs;
00349        unsigned n_recs;
00350        unsigned i;
00351        char *new_name;
00352        int new_fd;
00353        char *p;
00354        time_t now;
00355        FILE *new_fp;
00356 
00357        unlink(CHANGEDFILE);
00358        time(&now);
00359        if (createcache(pcp, &recs, &n_recs, now, now + 5 * 24 * 60 * 60))
00360               return;
00361 
00362        new_fd=maildir_createmsg(INBOX, "cache", &new_name);
00363        if (new_fd < 0 || (new_fp=fdopen(new_fd, "w")) == 0)
00364        {
00365               if (new_fd >= 0)        close(new_fd);
00366               destroycache(recs, n_recs);
00367               return;
00368        }
00369 
00370         p=malloc(sizeof("tmp/")+strlen(new_name));
00371         if (!p)
00372         {
00373               fclose(new_fp);
00374                 free(new_name);
00375               destroycache(recs, n_recs);
00376                 return;
00377         }
00378         strcat(strcpy(p, "tmp/"), new_name);
00379         free(new_name);
00380         new_name=p;
00381 
00382        /* Save a max of 5 events, for the main page listing */
00383 
00384        for (i=0; i<n_recs && i < 5; i++)
00385        {
00386               char buf1[NUMBUFSIZE], buf2[NUMBUFSIZE];
00387 
00388               fprintf(new_fp, "%s\t%s\t%s\t%s\t%s\n",
00389                      libmail_str_time_t(recs[i].start, buf1),
00390                      libmail_str_time_t(recs[i].end, buf2),
00391                      recs[i].eventid,
00392                      recs[i].flags,
00393                      recs[i].subject);
00394        }
00395 
00396        if (fflush(new_fp) || ferror(new_fp))
00397        {
00398               fclose(new_fp);
00399               unlink(new_name);
00400                 free(new_name);
00401               destroycache(recs, n_recs);
00402                 return;
00403         }
00404        fclose(new_fp);
00405        rename(new_name, CACHE);
00406        free(new_name);
00407        destroycache(recs, n_recs);
00408        return;
00409 }
00410 
00411 struct cacherecord_list {
00412        struct cacherecord_list *next;
00413        struct cacherecord rec;
00414 } ;
00415 
00416 static int cmp_reclist(const void *a, const void *b)
00417 {
00418        struct cacherecord_list *aa=*(struct cacherecord_list **)a;
00419        struct cacherecord_list *bb=*(struct cacherecord_list **)b;
00420 
00421        return ( aa->rec.end < bb->rec.end ? -1:
00422                aa->rec.end > bb->rec.end ? 1:
00423                aa->rec.start < bb->rec.start ? -1:
00424                aa->rec.start > bb->rec.start ? 1:
00425                strcmp(aa->rec.eventid, bb->rec.eventid));
00426 }
00427 
00428 static int callback_createcache(struct PCP_list_all *, void *);
00429 static int callback_retr_status(struct PCP_retr *, int, void *);
00430 static int callback_retr_headers(struct PCP_retr *, const char *,
00431                              const char *, void *);
00432 
00433 static void destroycache_rec(struct cacherecord *);
00434 
00435 struct retr_xinfo {
00436        struct cacherecord *recs;
00437        unsigned n_recs;
00438 } ;
00439 
00440 static int createcache(struct PCP *pcp,
00441                      struct cacherecord **recs, unsigned *n_recs,
00442                      time_t start, time_t end)
00443 {
00444        struct cacherecord_list *list=NULL, *p, **a;
00445        struct PCP_list_all la;
00446        struct PCP_retr r;
00447        struct retr_xinfo xr;
00448 
00449        unsigned i,n;
00450        const char **event_ids;
00451 
00452        *recs=0;
00453        *n_recs=0;
00454 
00455        memset(&la, 0, sizeof(la));
00456        la.list_from=start;
00457        la.list_to=end;
00458        la.callback_func=callback_createcache;
00459        la.callback_arg= &list;
00460 
00461        if (pcp_list_all(pcp, &la))
00462        {
00463               while ((p=list) != NULL)
00464               {
00465                      list=p->next;
00466                      destroycache_rec(&p->rec);
00467                      free(p);
00468               }
00469               return (0);
00470        }
00471 
00472        /* Sort the returned event list, in chronological order. */
00473 
00474 
00475        /* First, create an array out of the list */
00476 
00477        for (n=0, p=list; p; p=p->next)
00478               ++n;
00479 
00480        if (!n)
00481               return (0);   /* Nothing */
00482 
00483        a=malloc(sizeof(struct cacherecord_list *)*n);
00484        if (!a)
00485        {
00486               fprintf(stderr, "NOTICE: malloc failed\n");
00487 
00488               while ((p=list) != NULL)
00489               {
00490                      list=p->next;
00491                      destroycache_rec(&p->rec);
00492                      free(p);
00493               }
00494               return (-1);
00495        }
00496        for (n=0, p=list; p; p=p->next)
00497               a[n++]=p;
00498 
00499        /* Sort it, copy the sorted array to the return ptr */
00500 
00501        qsort(a, n, sizeof(*a), cmp_reclist);
00502 
00503        if ((*recs=malloc(sizeof(struct cacherecord)*n)) == NULL)
00504        {
00505               fprintf(stderr, "NOTICE: malloc failed\n");
00506 
00507               while ((p=list) != NULL)
00508               {
00509                      list=p->next;
00510                      destroycache_rec(&p->rec);
00511                      free(p);
00512               }
00513               free(a);
00514               return (-1);
00515        }
00516 
00517        for (i=0; i<n; i++)
00518               (*recs)[i]= a[i]->rec;
00519        *n_recs=n;
00520        free(a);
00521        while ((p=list) != NULL)
00522        {
00523               list=p->next;
00524               free(p);
00525        }
00526 
00527        /* Get the subject of all the events */
00528 
00529        event_ids=malloc(sizeof(const char *)*(n+1));
00530 
00531        if (!event_ids)
00532        {
00533               fprintf(stderr, "NOTICE: malloc failed\n");
00534 
00535               destroycache(*recs, *n_recs);
00536               return (-1);
00537        }
00538 
00539        for (i=0; i< *n_recs; i++)
00540               event_ids[i]= (*recs)[i].eventid;
00541        event_ids[i]=NULL;
00542 
00543        memset(&r, 0, sizeof(r));
00544        r.event_id_list=event_ids;
00545        r.callback_arg=&xr;
00546        xr.recs= *recs;
00547        xr.n_recs= *n_recs;
00548 
00549        r.callback_retr_status=callback_retr_status;
00550        r.callback_headers_func=callback_retr_headers;
00551 
00552        if (pcp_retr(pcp, &r))
00553        {
00554               fprintf(stderr, "NOTICE: pcp_retr: error: %s\n", pcp_errmsg(pcp));
00555               free(event_ids);
00556               destroycache(*recs, *n_recs);
00557               return (-1);
00558        }
00559        free(event_ids);
00560        return (0);
00561 }
00562 
00563 /* Callback from PCP LIST - save the event ID in the cacherecord_list */
00564 
00565 static int callback_createcache(struct PCP_list_all *a, void *vp)
00566 {
00567        struct cacherecord_list **listp=(struct cacherecord_list **)vp, *p;
00568 
00569        if ((p=malloc(sizeof(struct cacherecord_list))) == NULL)
00570               return (-1);
00571 
00572        p->rec.start=a->event_from;
00573        p->rec.end=a->event_to;
00574 
00575        if ((p->rec.eventid=strdup(a->event_id)) == NULL)
00576        {
00577               free(p);
00578               return (-1);
00579        }
00580 
00581        /* Initialize the other fields, so all ptrs are live */
00582 
00583        if ((p->rec.flags=strdup("")) == NULL)
00584        {
00585               free(p->rec.eventid);
00586               free(p);
00587               return (-1);
00588        }
00589 
00590        if ((p->rec.subject=strdup("")) == NULL)
00591        {
00592               free(p->rec.flags);
00593               free(p->rec.eventid);
00594               free(p);
00595               return (-1);
00596        }
00597 
00598        p->next= *listp;
00599        *listp=p;
00600        return (0);
00601 }
00602 
00603 static int callback_retr_status(struct PCP_retr *r, int s, void *vp)
00604 {
00605        struct cacherecord *recs=( (struct retr_xinfo *)vp)->recs;
00606        unsigned n_recs=( (struct retr_xinfo *)vp)->n_recs;
00607        unsigned i;
00608 
00609        char stat_buf[256];
00610        char *p;
00611 
00612        stat_buf[0]=0;
00613 
00614        if (s & LIST_CANCELLED)
00615        {
00616               strcat(stat_buf, " CANCELLED");
00617        }
00618 
00619        if (s & LIST_BOOKED)
00620        {
00621               strcat(stat_buf, " BOOKED");
00622        }
00623 
00624        p=stat_buf;
00625        if (*p)
00626               ++p;
00627 
00628        for (i=0; i<n_recs; i++)
00629        {
00630               if (strcmp(recs[i].eventid, r->event_id) == 0)
00631               {
00632                      char *s=strdup(p);
00633 
00634                      if (!s)
00635                             return (-1);
00636                      free(recs[i].flags);
00637                      recs[i].flags=s;
00638                      break;
00639               }
00640        }
00641        return (0);
00642 }
00643 
00644 /* RETR callback for headers - save the Subject: header */
00645 
00646 static void collapse_subject(char *s)
00647 {
00648        /* Collapse multiline subjects */
00649 
00650        char *t, *u;
00651 
00652        for (t=u=s; *t; )
00653        {
00654               if (*t != '\n')
00655               {
00656                      *u++=*t++;
00657                      continue;
00658               }
00659 
00660               while (*t && isspace((int)(unsigned char)*t))
00661                      ++t;
00662               *u++=' ';
00663        }
00664        *u=0;
00665 }
00666 
00667 static int callback_retr_headers(struct PCP_retr *r, const char *h,
00668                              const char *v, void *vp)
00669 {
00670        struct cacherecord *recs=( (struct retr_xinfo *)vp)->recs;
00671        unsigned n_recs=( (struct retr_xinfo *)vp)->n_recs;
00672        unsigned i;
00673 
00674        if (strcasecmp(h, "Subject") || !v)
00675               return (0);
00676 
00677        for (i=0; i<n_recs; i++)
00678        {
00679               if (strcmp(recs[i].eventid, r->event_id) == 0)
00680               {
00681                      char *s;
00682 
00683                      s=strdup(v);
00684 
00685                      if (!s)
00686                             return (-1);
00687 
00688                      collapse_subject(s);
00689                      free(recs[i].subject);
00690                      recs[i].subject=s;
00691               }
00692        }
00693 
00694        return (0);
00695 }
00696 
00697 static void destroycache(struct cacherecord *c, unsigned n)
00698 {
00699        unsigned i;
00700 
00701        for (i=0; i<n; i++)
00702        {
00703               destroycache_rec(c+i);
00704        }
00705        if (c)
00706               free(c);
00707 }
00708 
00709 static void destroycache_rec(struct cacherecord *c)
00710 {
00711        free(c->eventid);
00712        free(c->flags);
00713        free(c->subject);
00714 }
00715 
00716 static void parsecache_rec(char *p, struct cacherecord *cr)
00717 {
00718        unsigned long a;
00719 
00720        memset(cr, 0, sizeof(*cr));
00721        cr->eventid="";
00722        cr->flags="";
00723        cr->subject="";
00724 
00725        if (!p || sscanf(p, "%lu", &a) <= 0)
00726               return;
00727        p=strchr(p, '\t');
00728        cr->start= (time_t)a;
00729        if (!p || sscanf(p, "%lu", &a) <= 0)
00730               return;
00731        cr->end= (time_t)a;
00732        p=strchr(p+1, '\t');
00733        if (!p) return;
00734        ++p;
00735 
00736        cr->eventid=p;
00737        p=strchr(p, '\t');
00738        if (!p) return;
00739        *p++=0;
00740 
00741        cr->flags=p;
00742        p=strchr(p, '\t');
00743        if (!p) return;
00744        *p++=0;
00745 
00746        cr->subject=p;
00747 }
00748 
00749 struct PCP *sqpcp_calendar()
00750 {
00751        const char *p;
00752 
00753        if (!sqpcp_mode())
00754        {
00755               errno=ENOENT;
00756               return (NULL);
00757        }
00758 
00759        if (calendar)
00760               return (calendar);
00761 
00762        p=getenv("AUTHADDR");
00763 
00764        if (!p)
00765        {
00766               errno=ENOENT;
00767               return (NULL);
00768        }
00769 
00770        if (sqpcp_has_groupware())
00771        {
00772               char token[256];
00773               char *pp;
00774 
00775               FILE *f=fopen(TOKEN, "r");
00776 
00777               if (!f)
00778                      return (NULL);
00779 
00780               if (fgets(token, sizeof(token), f) == NULL)
00781               {
00782                      fclose(f);
00783                      return (NULL);
00784               }
00785 
00786               if ((pp=strchr(token, '\n')) != 0) *pp=0;
00787 
00788               fclose(f);
00789               if (token[0] == 0)
00790               {
00791                      unlink(TOKEN);
00792                      return (NULL);
00793               }
00794 
00795               calendar=pcp_reopen_server(p, token, NULL);
00796 
00797               if (calendar)
00798               {
00799                      p=pcp_authtoken(calendar);
00800 
00801                      if (p && strcmp(p, token))
00802                      {
00803                             int u=umask(077);
00804 
00805                             /* Save new authentication token */
00806 
00807                             f=fopen(TOKEN, "w");
00808                             umask(u);
00809                             if (f)
00810                             {
00811                                    fprintf(f, "%s\n", token);
00812                                    fclose(f);
00813                             }
00814                      }
00815               }
00816               else
00817               {
00818                      unlink(TOKEN);
00819               }
00820               return (calendar);
00821        }
00822 
00823        return ((calendar=pcp_open_dir("calendar", p)));
00824 }
00825 
00826 
00827 /* ---------------------------------------------------------------- */
00828 /* Display event information */
00829 /* ---------------------------------------------------------------- */
00830 
00831 static struct PCP_event_time *event_time_list=0;
00832 static unsigned n_event_time_list=0;
00833 static FILE *openoldfp(const char *p, unsigned long *prev_size);
00834 
00835 struct my_participant {
00836        struct my_participant *next;
00837        char *name;
00838        char *address;
00839 } ;
00840 
00841 static struct my_participant *my_participant_list=0;
00842 
00843 static void add_my_participant(const char *h)
00844 {
00845        struct my_participant *m=
00846               malloc(sizeof(struct my_participant));
00847 
00848        if (!m)
00849               enomem();
00850 
00851        memset(m, 0, sizeof(*m));
00852        m->next=my_participant_list;
00853        my_participant_list=m;
00854 
00855        if ((m->address=strdup(h)) == NULL)
00856               enomem();
00857 }
00858 
00859 static char *from_buf=0, *subj_buf=0;
00860 
00861 void sqpcp_eventstart()
00862 {
00863        const char *p=cgi("draftmessage");
00864        FILE *oldfp;
00865        struct rfc822hdr h;
00866        struct PCP_event_time_list {
00867               struct PCP_event_time_list *next;
00868               struct PCP_event_time t;
00869        } *event_time_listp=NULL, **lastp= &event_time_listp;
00870        unsigned event_time_list_cnt=0;
00871 
00872        sqpcp_eventend();
00873 
00874        if (!p || !*p)
00875               return;
00876 
00877        oldfp=openoldfp(p, NULL);
00878        if (!oldfp)
00879               return;
00880 
00881        rfc822hdr_init(&h, 8192);
00882        while (rfc822hdr_read(&h, oldfp, NULL, 0) == 0)
00883        {
00884               if (strcasecmp(h.header, "X-Event-Time") == 0 && h.value)
00885               {
00886                      unsigned long n1, n2;
00887 
00888                      if (sscanf(h.value, "%lu %lu", &n1, &n2) == 2)
00889                      {
00890                             struct PCP_event_time_list *t=
00891                                    malloc(sizeof(**lastp));
00892 
00893                             if (!t)
00894                             {
00895                                    rfc822hdr_free(&h);
00896                                    sqpcp_eventend();
00897                                    enomem();
00898                                    return;
00899                             }
00900                             *lastp=t;
00901                             t->next=NULL;
00902                             t->t.start=(time_t)n1;
00903                             t->t.end=(time_t)n2;
00904                             ++event_time_list_cnt;
00905                             lastp=&t->next;
00906                      }
00907               }
00908               else if (strcasecmp(h.header, "X-Event-Participant") == 0 && h.value)
00909               {
00910                      add_my_participant(h.value);
00911               }
00912               else if (strcasecmp(h.header, "from") == 0 && h.value)
00913               {
00914                      rfc822hdr_collapse(&h);
00915                      if (from_buf)
00916                             free(from_buf);
00917 
00918                      from_buf=NULL;
00919 
00920                      if ((from_buf=
00921                           rfc822_display_hdrvalue_tobuf(h.header,
00922                                                     h.value,
00923                                                     sqwebmail_content_charset,
00924                                                     NULL, NULL)) == NULL)
00925                             from_buf=strdup(h.value);
00926 
00927                      if (from_buf)
00928                             cgi_put("from", from_buf);
00929               }
00930               else if (strcasecmp(h.header, "subject") == 0 && h.value)
00931               {
00932                      rfc822hdr_collapse(&h);
00933                      if (subj_buf)
00934                             free(subj_buf);
00935 
00936                      subj_buf=rfc822_display_hdrvalue_tobuf(h.header,
00937                                                         h.value,
00938                                                         sqwebmail_content_charset,
00939                                                         NULL, NULL);
00940                      if (!subj_buf)
00941                             subj_buf=strdup(subj_buf);
00942 
00943                      if (subj_buf)
00944                             cgi_put("headersubject", subj_buf);
00945               }
00946        }
00947        rfc822hdr_free(&h);
00948        if (event_time_list_cnt)
00949        {
00950               struct PCP_event_time *list1;
00951               struct PCP_event_time_list *p;
00952 
00953               list1=malloc(sizeof(struct PCP_event_time_list)
00954                           *event_time_list_cnt);
00955               if (!list1)
00956               {
00957                      sqpcp_eventend();
00958                      enomem();
00959                      return;
00960               }
00961               event_time_list_cnt=0;
00962               while ((p=event_time_listp) != NULL)
00963               {
00964                      list1[event_time_list_cnt]=p->t;
00965                      ++event_time_list_cnt;
00966                      event_time_listp=p->next;
00967                      free(p);
00968               }
00969 
00970               event_time_list=list1;
00971               n_event_time_list=event_time_list_cnt;
00972        }
00973 }
00974 
00975 void sqpcp_eventend()
00976 {
00977        struct my_participant *m;
00978 
00979        while ((m=my_participant_list) != NULL)
00980        {
00981               my_participant_list=m->next;
00982               if (m->name)
00983                      free(m->name);
00984               if (m->address)
00985                      free(m->address);
00986               free(m);
00987        }
00988 
00989        if (event_time_list)
00990               free(event_time_list);
00991        event_time_list=NULL;
00992        n_event_time_list=0;
00993 
00994 }
00995 
00996 void sqpcp_eventtimes()
00997 {
00998        char buffer[512];
00999        unsigned i;
01000 
01001        for (i=0; i<n_event_time_list; i++)
01002        {
01003               if (i)
01004                      printf("<br />\n");
01005               if (pcp_fmttimerange(buffer, sizeof(buffer),
01006                                  event_time_list[i].start,
01007                                  event_time_list[i].end))
01008                      continue;
01009               printf("<span class=\"tt\">");
01010               print_safe(buffer);
01011               printf("&nbsp;&nbsp;</span><a href=\"");
01012               output_scriptptrget();
01013               printf("&amp;form=newevent&amp;draftmessage=");
01014               output_urlencoded(cgi("draftmessage"));
01015               printf("&amp;do.deleventtime=%s-%s\"><font size=\"-2\">"
01016                      "(%s)</font></a>",
01017                      libmail_str_time_t(event_time_list[i].start, buffer),
01018                      libmail_str_time_t(event_time_list[i].end, buffer+NUMBUFSIZE),
01019                      getarg("REMOVE")
01020                      );
01021        }
01022 }
01023 
01024 static int save_participant_names(const char *addr, const char *name,
01025                               void *vp)
01026 {
01027        struct my_participant *p=(struct my_participant *)vp;
01028 
01029        for ( ; name && p; p=p->next)
01030               if (strcasecmp(p->address, addr) == 0 && p->name == 0)
01031                      p->name=strdup(name);
01032        return (0);
01033 }
01034 
01035 void sqpcp_eventparticipants()
01036 {
01037        struct my_participant *m;
01038 
01039        if (!my_participant_list)
01040               return;
01041 
01042        (void)ab_get_nameaddr(save_participant_names, my_participant_list);
01043 
01044        printf("<table border=\"0\">");
01045 
01046        for (m=my_participant_list; m; m=m->next)
01047        {
01048               printf("<tr><td><span class=\"tt\">");
01049               if (m->address)
01050                      ab_nameaddr_show(m->name, m->address);
01051 
01052               printf("</span></td><td>&nbsp;&nbsp;<a href=\"");
01053 
01054               output_scriptptrget();
01055               printf("&amp;form=newevent&amp;draftmessage=");
01056               output_urlencoded(cgi("draftmessage"));
01057               printf("&amp;do.delparticipant=");
01058               output_urlencoded(m->address);
01059               printf("\"><font size=\"-2\">(%s)</font></a></td></tr>\n",
01060                      getarg("REMOVE"));
01061        }
01062        printf("</table>");
01063 }
01064 
01065 void sqpcp_eventfrom()
01066 {
01067        if (auth_getoptionenvint("wbnochangingfrom"))
01068        {
01069               printf("<span class=\"tt\">");
01070               print_safe(login_fromhdr());
01071               printf("</span>");
01072        }
01073        else
01074        {
01075               const char *p=cgi("headerfrom");
01076 
01077               if (!p || !*p)
01078                      p=pref_from;
01079               if (!p || !*p)
01080                      p=login_fromhdr();
01081               if (!p)
01082                      p="";
01083 
01084               printf("<input type=\"text\" name=\"headerfrom\" size=\"60\" value=\"");
01085               output_attrencoded(p);
01086               printf("\" />");
01087        }
01088 }
01089 
01090 void sqpcp_eventtext()
01091 {
01092        const char *p;
01093 
01094        printf("<textarea name=\"message\" cols=\"%d\" rows=\"15\" wrap=\"soft\">",
01095               MYLINESIZE);
01096        p=cgi("draftmessage");
01097 
01098        if (p && *p)
01099        {
01100               FILE *fp=openoldfp(p, NULL);
01101               int dummy;
01102 
01103               if (fp)
01104               {
01105                      newmsg_showfp(fp, &dummy);
01106               }
01107               fclose(fp);
01108        }
01109        printf("</textarea>\n");
01110 }
01111 
01112 void sqpcp_eventattach()
01113 {
01114        const char *p;
01115 
01116        p=cgi("draftmessage");
01117 
01118        if (p && *p)
01119        {
01120               attachments_head(NULL, cgi("pos"), p);
01121        }
01122 }
01123 
01124 /* ------- Display the cached event summary -------- */
01125 
01126 static void print_event_subject(char *, const char *, unsigned);
01127 static void print_event_link_url(const char *, const char *);
01128 
01129 void sqpcp_summary()
01130 {
01131        FILE *fp;
01132        int cnt=0;
01133        time_t now;
01134        struct tm *tmptr;
01135 
01136        if (!sqpcp_mode())
01137               return;
01138 
01139        if (*cgi("do.calendarlogin"))
01140        {
01141               const char *userid=getenv("AUTHADDR");
01142               const char *password=cgi("password");
01143 
01144               if (userid && password)
01145               {
01146                      do_pcplogin(userid, password, 1);
01147               }
01148        }
01149 
01150        if (sqpcp_has_groupware())
01151        {
01152               if (!sqpcp_loggedin())
01153               {
01154                      insert_include("calendarlogin");
01155                      return;
01156               }
01157        }
01158 
01159        time(&now);
01160        tmptr=localtime(&now);
01161 
01162        if (tmptr)
01163        {
01164               char *p=scriptptrget();
01165               char *q=malloc(strlen(p)+200);
01166 
01167               if (!q)
01168               {
01169                      free(p);
01170                      enomem();
01171               }
01172 
01173               strcpy(q, p);
01174               free(p);
01175               strcat(q, "&amp;form=eventdaily&amp;clearcache=1&amp;date=");
01176               sprintf(q+strlen(q), "%04d%02d%02d",
01177                      tmptr->tm_year + 1900,
01178                      tmptr->tm_mon+1,
01179                      tmptr->tm_mday);
01180 
01181               printf(getarg("CALENDAR"), q);
01182               free(q);
01183        }
01184 
01185        printf("<table class=\"eventsummary\" width=\"100%%\">");
01186 
01187        if ((fp=fopen(CACHE, "r")) != NULL)
01188        {
01189               char buffer[BUFSIZ];
01190               int i;
01191               char last_date[256];
01192               char date[256];
01193               char date2[256];
01194               struct tm *tm;
01195               char yyyymmdd[9];
01196 
01197               char time1[128];
01198               char time2[128];
01199 
01200               last_date[0]=0;
01201 
01202               for (;;)
01203               {
01204                      int c;
01205                      struct cacherecord cr;
01206 
01207                      i=0;
01208 
01209                      while ((c=getc(fp)) != EOF && c != '\n')
01210                      {
01211                             if (i < sizeof(buffer)-1)
01212                                    buffer[i++]=(char)c;
01213                      }
01214                      buffer[i]=0;
01215                      if (i == 0 && c == EOF)
01216                             break;
01217 
01218                      parsecache_rec(buffer, &cr);
01219 
01220                      if (pcp_fmttime(date, sizeof(date),
01221                                    cr.start, FMTTIME_DATE))
01222                             continue;
01223                      if (pcp_fmttime(date2, sizeof(date2),
01224                                    cr.end, FMTTIME_DATE))
01225                             continue;
01226 
01227                      if (pcp_fmttime(time1, sizeof(time1),
01228                                    cr.start,
01229                                    FMTTIME_TIME))
01230                             continue;
01231 
01232                      if (pcp_fmttime(time2,
01233                                    sizeof(time2),
01234                                    cr.end,
01235                                    FMTTIME_TIME))
01236                             continue;
01237 
01238                      tm=localtime(&cr.start);
01239                      if (!tm)
01240                             continue;
01241                      sprintf(yyyymmdd, "%04d%02d%02d",
01242                             tm->tm_year + 1900,
01243                             tm->tm_mon + 1,
01244                             tm->tm_mday);
01245 
01246                      i=0;
01247                      if (last_date[0] && strcmp(last_date, date) == 0)
01248                      {
01249                             if (strcmp(last_date, date2) == 0)
01250                             {
01251                                    /* Same day as last event */
01252 
01253                                    printf("<tr><td align=\"left\" width=\"1%%\">&nbsp;</td>"
01254                                           "<td align=\"left\">&nbsp;"
01255                                           "<a href=\"");
01256                                    print_event_link_url(cr.eventid, "");
01257                                    printf("&amp;date=%s\">", yyyymmdd);
01258                                    print_safe(time1);
01259                                    printf("&nbsp;-&nbsp;");
01260                                    print_safe(time2);
01261                                    printf("</a></td>");
01262                                    i=1;
01263                             }
01264                             else
01265                             {
01266                                    last_date[0]=0;
01267                             }
01268                      }
01269                      else
01270                      {
01271                             last_date[0]=0;
01272                             if (strcmp(date, date2) == 0)
01273                                    strcpy(last_date, date);
01274                      }
01275 
01276                      if (!i)
01277                      {
01278                             if (cnt)
01279                                    printf("<tr><td style=\"line-height: 0px; font-size: 8px\" colspan=\"3\">"
01280                                           "&nbsp;"
01281                                           "</td></tr>\n");
01282                             if (strcmp(date, date2))
01283                             {
01284                                    printf("<tr><td colspan=\"2\">"
01285                                           "<a href=\"");
01286                                    print_event_link_url(cr.eventid, "");
01287                                    printf("&amp;date=%s\">", yyyymmdd);
01288                                    print_safe(date);
01289                                    printf("&nbsp;");
01290                                    print_safe(time1);
01291                                    printf("&nbsp;-&nbsp;");
01292                                    print_safe(date2);
01293                                    printf("&nbsp;");
01294                                    print_safe(time2);
01295                                    printf("</a></td>");
01296                             }
01297                             else
01298                             {
01299                                    printf("<tr><td width=\"1%%\">"
01300                                           "<a href=\"");
01301                                    print_event_link_url(cr.eventid, "");
01302                                    printf("&amp;date=%s\">", yyyymmdd);
01303                                    print_safe(date);
01304                                    printf("</a></td><td>&nbsp;"
01305                                           "<a href=\"");
01306                                    print_event_link_url(cr.eventid, "");
01307                                    printf("&amp;date=%s\">", yyyymmdd);
01308                                    print_safe(time1);
01309                                    printf("&nbsp;-&nbsp;");
01310                                    print_safe(time2);
01311                                    printf("</a></td>");
01312                             }
01313                      }
01314 
01315                      printf("<td width=\"100%%\">"
01316                             "<a href=\"");
01317                      print_event_link_url(cr.eventid, "");
01318                      printf("&amp;date=%s\">&nbsp;&nbsp;", yyyymmdd);
01319                      print_event_subject(cr.flags, cr.subject, 60);
01320                      printf("</a></td></tr>\n");
01321                      ++cnt;
01322               }
01323               fclose(fp);
01324        }
01325 
01326        if (cnt == 0)
01327        {
01328               printf("<tr><td align=\"center\">%s</td></tr>\n",
01329                      getarg("NOEVENTS"));
01330        }
01331 
01332        printf("</table>\n");
01333        printf("<a href=\"");
01334        output_scriptptrget();
01335        printf("&amp;form=newevent\">%s</a>", getarg("NEWEVENT"));
01336 }
01337 
01338 
01339 static void print_event_subject(char *flags, const char *subject, unsigned w)
01340 {
01341        unsigned i;
01342        char *p;
01343 
01344        /* Print event flags first: CANCELLED... */
01345 
01346        for (p=flags; p && (p=strtok(p, " \t\r")) != 0; p=0)
01347        {
01348               printf("%s", getarg(p));
01349        }
01350 
01351        p=rfc822_display_hdrvalue_tobuf("subject",
01352                                    subject ? subject:"",
01353                                    sqwebmail_content_charset,
01354                                    NULL,
01355                                    NULL);
01356 
01357        if (!p)
01358               p=strdup(subject ? subject:"");
01359 
01360        if (!p)
01361               return;
01362 
01363        if (strlen(p) > w)
01364        {
01365               /* Truncate long subject lines */
01366               i=w-5;
01367               while (i)
01368               {
01369                      if (isspace((int)(unsigned char) p[i]))
01370                      {
01371                             strcpy(p+i, "...");
01372                             break;
01373                      }
01374                      --i;
01375               }
01376        }
01377        print_safe(p);
01378        free(p);
01379 }
01380 
01381 /* ------- New event support code -------- */
01382 
01383 static int addtime(int);
01384 static void addparticipant(int, const char *);
01385 
01386 static FILE *openoldfp(const char *p, unsigned long *prev_size)
01387 {
01388        struct stat stat_buf;
01389        char *filename;
01390        int x;
01391        FILE *oldfp;
01392 
01393        CHECKFILENAME(p);
01394 
01395        filename=maildir_find(INBOX "." DRAFTS, p);
01396        if (!filename)
01397               return (NULL);
01398 
01399        x=maildir_safeopen(filename, O_RDONLY, 0);
01400        free(filename);
01401        if (x < 0)
01402               return (NULL);
01403 
01404 
01405        if (fstat(x, &stat_buf) < 0 || (oldfp=fdopen(x, "r")) == NULL)
01406        {
01407               close(x);
01408               return (NULL);
01409        }
01410 
01411        if (prev_size)
01412               *prev_size=stat_buf.st_size;
01413        return (oldfp);
01414 }
01415 
01416 
01417 /* ------------- Conflict indicators ---------------- */
01418 
01419 struct conflict_list {
01420        struct conflict_list *next;
01421        char *event_id;
01422        time_t start, end;
01423        char *address;
01424        char *subject;
01425 } ;
01426 
01427 static struct conflict_list *conflict_list=NULL;
01428 
01429 static void init_save_conflict()
01430 {
01431        while (conflict_list)
01432        {
01433               struct conflict_list *p=conflict_list;
01434 
01435               conflict_list=p->next;
01436               if (p->event_id)
01437                      free(p->event_id);
01438               if (p->address)
01439                      free(p->address);
01440               if (p->subject)
01441                      free(p->subject);
01442               free(p);
01443        }
01444 }
01445 
01446 static int save_conflict(const char *event_id, time_t start, time_t end,
01447                        const char *address,
01448                        void *dummy)
01449 {
01450        struct conflict_list *p, **ptr;
01451 
01452        for (ptr= &conflict_list; *ptr; ptr=&(*ptr)->next)
01453        {
01454               if ( (*ptr)->end > end)
01455                      break;
01456        }
01457 
01458        if ((p=malloc(sizeof(struct conflict_list))) == NULL)
01459               return (-1);
01460        memset(p, 0, sizeof(*p));
01461        p->next= *ptr;
01462        *ptr=p;
01463 
01464        p->start=start;
01465        p->end=end;
01466        if ((p->event_id=strdup(event_id)) == NULL ||
01467            (address && (p->address=strdup(address)) == NULL))
01468               return (-1);
01469 
01470        return (0);
01471 }
01472 
01473 static int save_conflict_subj(struct PCP_retr *, const char *,
01474                            const char *, void *);
01475 
01476 static void show_conflict_error(struct PCP *pcp)
01477 {
01478        unsigned n;
01479        struct conflict_list *p;
01480        const char **l;
01481        struct PCP_retr r;
01482 
01483        for (n=0, p=conflict_list; p; p=p->next)
01484               if (p->event_id && (!p->address ||
01485                                 strcmp(p->address, "@") == 0))
01486                      ++n;
01487 
01488        if ((l=malloc(sizeof(const char *)*(n+1))) == NULL)
01489               return;
01490 
01491        for (n=0, p=conflict_list; p; p=p->next)
01492               if (p->event_id && (!p->address ||
01493                                 strcmp(p->address, "@") == 0))
01494               {
01495                      l[n]=p->event_id;
01496                      ++n;
01497               }
01498 
01499        l[n]=0;
01500        memset(&r, 0, sizeof(r));
01501        r.event_id_list=l;
01502        r.callback_headers_func=save_conflict_subj;
01503 
01504        if (n == 0 || pcp_retr(pcp, &r) == 0)
01505        {
01506               printf("<table border=\"0\" width=\"100%%\" class=\"small-error\">");
01507               for (p=conflict_list; p; p=p->next)
01508               {
01509                      char buffer[512];
01510 
01511                      printf("<tr><td width=\"30\">&nbsp;</td><td><span class=\"tt\">");
01512                      if (pcp_fmttimerange(buffer, sizeof(buffer),
01513                                         p->start,
01514                                         p->end) == 0)
01515                      {
01516                             print_safe(buffer);
01517                      }
01518                      printf("</span></td><td width=\"30\">&nbsp;</td><td width=\"100%%\"><span class=\"tt\">");
01519                      if (p->address && strcmp(p->address, "@"))
01520                      {
01521                             printf(getarg("CONFLICTERR2"));
01522                             print_safe(p->address);
01523                      }
01524                      else
01525                             print_event_subject("", p->subject
01526                                               ? p->subject:"", 60);
01527                      printf("</span></td></tr>\n");
01528               }
01529               printf("<tr><td colspan=\"4\"><hr width=\"90%%\" /></td></tr></table>\n");
01530        }
01531        free(l);
01532        init_save_conflict();
01533 }
01534 
01535 static int save_conflict_subj(struct PCP_retr *r, const char *h,
01536                            const char *v, void *dummy)
01537 {
01538        struct conflict_list *p;
01539 
01540        if (strcasecmp(h, "subject") || !v)
01541               return (0);
01542 
01543        for (p=conflict_list; p; p=p->next)
01544               if (p->event_id && strcmp(p->event_id, r->event_id) == 0)
01545               {
01546                      if (p->subject)
01547                             free(p->subject);
01548                      if ((p->subject=strdup(v)) != NULL)
01549                             collapse_subject(p->subject);
01550                      break;
01551               }
01552        return (0);
01553 }
01554 
01555 /* -------------------------------------------------- */
01556 
01557 static void showerror()
01558 {
01559        const char *p;
01560 
01561        p=cgi("error");
01562        if (strcmp(p, "quota") == 0)
01563               printf("%s", getarg("QUOTAERR"));
01564        if (strcmp(p, "time") == 0)
01565               printf("%s", getarg("NOTIMEERR"));
01566        if (strcmp(p, "conflict") == 0)
01567        {
01568               struct PCP *pcp=sqpcp_calendar();
01569 
01570               printf("%s", getarg("CONFLICTERR"));
01571               if (pcp)
01572                      show_conflict_error(pcp);
01573        }
01574        if (strcmp(p, "calendar") == 0)
01575        {
01576               printf(getarg("CALENDARERR"), cgi("pcperror"));
01577        }
01578        if (strcmp(p, "locked") == 0)
01579               printf("%s", getarg("LOCKERR"));
01580        if (strcmp(p, "notfound") == 0)
01581               printf("%s", getarg("NOTFOUNDERR"));
01582        if (strcmp(p, "eventlocked") == 0)
01583               printf("%s", getarg("EVENTLOCKEDERR"));
01584 }
01585 
01586 #if 0
01587 /*
01588 ** Create/Estimate the To: header which lists event participants.
01589 */
01590 
01591 static void mktohdr(char *h, size_t *sizep)
01592 {
01593        int need_toh=1;
01594        size_t l=0;
01595        struct my_participant *p;
01596 
01597        *sizep=4;
01598 
01599        for (p=my_participant_list; p; p=p->next)
01600        {
01601               const char *c;
01602 
01603               if (*sizep - l > 500)
01604               {
01605                      if (h)
01606                             *h++='\n';
01607                      ++*sizep;
01608                      need_toh=1;
01609                      l= *sizep;
01610               }
01611 
01612               if (need_toh)
01613               {
01614                      if (h)
01615                      {
01616                             strcpy(h, "To: ");
01617                             h += 4;
01618                      }
01619                      *sizep += 4;
01620                      need_toh=0;
01621               }
01622               else
01623               {
01624                      if (h)
01625                      {
01626                             strcpy(h, ",\n  ");
01627                             h += 4;
01628                      }
01629                      *sizep += 4;
01630               }
01631 
01632               if (p->name && *p->name)
01633               {
01634                      if (h)
01635                             *h++='"';
01636                      ++*sizep;
01637 
01638                      for (c=p->name; *c; c++)
01639                      {
01640                             if (*c == '"' || *c == '\\')
01641                             {
01642                                    if (h)
01643                                           *h++ = '\\';
01644                                    ++*sizep;
01645                             }
01646                             if (h)
01647                                    *h++ = *c;
01648                             ++*sizep;
01649                      }
01650 
01651                      if (h)
01652                      {
01653                             *h++='"';
01654                             *h++=' ';
01655                      }
01656                      *sizep += 2;
01657               }
01658 
01659               if (h)
01660                      *h++='<';
01661               ++*sizep;
01662 
01663               for (c=p->address; *c; c++)
01664               {
01665                      if (h)
01666                             *h++= *c;
01667                      ++*sizep;
01668               }
01669               if (h)
01670                      *h++='>';
01671               ++*sizep;
01672        }
01673 
01674        if (my_participant_list)
01675        {
01676               if (h)
01677                      *h++='\n';
01678               ++*sizep;
01679        }
01680 
01681        if (h)
01682               *h++=0;
01683        ++*sizep;
01684 }
01685 #endif
01686 
01687 void sqpcp_newevent()
01688 {
01689        char *draftfilename;
01690        int newdraftfd;
01691        const char *p;
01692        unsigned long prev_size=0;
01693        FILE *oldfp=NULL;
01694        int errflag=0;
01695        int do_newevent= *cgi("do.neweventtime") ? 1:0;
01696        int do_newparticipant= *cgi("do.addparticipant") ? 1:0;
01697        int do_delevent=0;
01698        int do_delparticipant= *cgi("do.delparticipant") ? 1:0;
01699        time_t delstart=0, delend=0;
01700 
01701        static char *draftmessage_buf=0;
01702 
01703        showerror();
01704 
01705        if (!do_newevent)
01706        {
01707               if ((p=cgi("do.deleventtime")) && *p)
01708               {
01709                      unsigned long a, b;
01710 
01711                      if (sscanf(p, "%lu-%lu", &a, &b) == 2)
01712                      {
01713                             delstart=(time_t)a;
01714                             delend=(time_t)b;
01715                             do_delevent=1;
01716                      }
01717               }
01718        }
01719 
01720        p=cgi("draftmessage");
01721 
01722        if (!do_newevent && !do_delevent && !do_newparticipant
01723            && !do_delparticipant)
01724        {
01725               if (*cgi("do.neweventpreview") && p && *p)
01726               {
01727                      printf("<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"1\" class=\"box-small-outer\"><tr><td>\n");
01728                      printf("<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"4\" class=\"preview\"><tr><td>\n");
01729                      newmsg_preview(p);
01730                      printf("</td></tr></table>\n");
01731                      printf("</td></tr></table>\n");
01732               }
01733               return;
01734        }
01735 
01736        if (p && *p)
01737        {
01738               oldfp=openoldfp(p, &prev_size);
01739               if (!oldfp)
01740                      p="";
01741        }
01742 
01743        if (p && *p)
01744        {
01745               newdraftfd=maildir_recreatemsg(INBOX "." DRAFTS, p, &draftfilename);
01746        }
01747        else
01748        {
01749               newdraftfd=maildir_createmsg(INBOX "." DRAFTS, 0, &draftfilename);
01750               maildir_writemsgstr(newdraftfd, "X-Event: 1\n");
01751 
01752               if (draftmessage_buf)
01753                      free(draftmessage_buf);
01754               if ((draftmessage_buf=strdup(draftfilename)) != 0)
01755                      cgi_put("draftmessage", draftmessage_buf);
01756        }
01757 
01758        if (do_newevent || do_delevent || do_newparticipant
01759            || do_delparticipant)
01760        {
01761               if (oldfp)
01762               {
01763                      struct rfc822hdr h;
01764 
01765                      rfc822hdr_init(&h, 8192);
01766                      while (rfc822hdr_read(&h, oldfp, NULL, 0) == 0)
01767                      {
01768                             unsigned long a, b;
01769                             if (do_delevent && strcasecmp(h.header,
01770                                                        "X-Event-Time")
01771                                 == 0 && h.value && sscanf(h.value,
01772                                                        "%lu %lu",
01773                                                        &a, &b) == 2)
01774 
01775                             {
01776                                    if ( (time_t)a == delstart &&
01777                                         (time_t)b == delend)
01778                                           continue;
01779                             }
01780 
01781                             if (do_delparticipant
01782                                 && strcasecmp(h.header, "X-Event-Participant")
01783                                 == 0 && h.value)
01784                             {
01785                                    if (strcmp(h.value,
01786                                              cgi("do.delparticipant"))
01787                                        == 0)
01788                                           continue;
01789                             }
01790                             if (strcasecmp(h.header,
01791                                           "X-Event-Participant") == 0 &&
01792                                 h.value)
01793                                    add_my_participant(h.value);
01794 
01795                             if (strcasecmp(h.header, "To") == 0)
01796                                    continue;
01797                             /* To: header rebuilt later */
01798 
01799                             maildir_writemsgstr(newdraftfd, h.header);
01800                             maildir_writemsgstr(newdraftfd, ": ");
01801                             maildir_writemsgstr(newdraftfd, h.value);
01802                             maildir_writemsgstr(newdraftfd, "\n");
01803                      }
01804                      rfc822hdr_free(&h);
01805 
01806               }
01807 
01808               if (do_newevent && addtime(newdraftfd))
01809               {
01810                      errflag=1;
01811                      printf("%s", getarg("TIMEERR"));
01812               }
01813 
01814               if (do_newparticipant)
01815               {
01816                      const char *p=cgi("addressbookname");
01817 
01818                      if (!*p)
01819                             p=cgi("participant1");
01820 
01821                      addparticipant(newdraftfd, p);
01822               }
01823 
01824               (void)ab_get_nameaddr(save_participant_names,
01825                                   my_participant_list);
01826 
01827 #if 0
01828               {
01829                      struct rfc822t *t;
01830                      struct rfc822a *a;
01831                      char *p;
01832                      char *tohdr;
01833                      size_t tohdr_size;
01834 
01835                      mktohdr(NULL, &tohdr_size);
01836 
01837                      tohdr=malloc(tohdr_size);
01838                      if (!tohdr)
01839                             enomem();
01840 
01841                      mktohdr(tohdr, &tohdr_size);
01842 
01843                      if ((t=rfc822t_alloc_new(tohdr, NULL, NULL)) == NULL)
01844                      {
01845                             free(tohdr);
01846                             enomem();
01847                      }
01848 
01849                      if ((a=rfc822a_alloc(t)) == NULL)
01850                      {
01851                             rfc822t_free(t);
01852                             free(tohdr);
01853                             enomem();
01854                      }
01855 
01856                      p=rfc2047_encode_header(a,sqwebmail_content_charset);
01857 
01858                      if (!p)
01859                      {
01860                             rfc822a_free(a);
01861                             rfc822t_free(t);
01862                             free(tohdr);
01863                             enomem();
01864                      }
01865                      free(tohdr);
01866                      tohdr=p;
01867                      rfc822a_free(a);
01868                      rfc822t_free(t);
01869 
01870                      maildir_writemsgstr(newdraftfd, tohdr);
01871                      maildir_writemsgstr(newdraftfd, "\n");
01872                      free(tohdr);
01873               }
01874 #endif
01875 
01876               sqpcp_eventend(); /* Deallocate participant list */
01877 
01878               maildir_writemsgstr(newdraftfd, "\n");
01879        }
01880 
01881        if (oldfp)
01882        {
01883               char buf[BUFSIZ];
01884               int n;
01885 
01886               while ((n=fread(buf, 1, sizeof(buf), oldfp)) > 0)
01887                      maildir_writemsg(newdraftfd, buf, n);
01888        }
01889 
01890        if (oldfp)
01891               fclose(oldfp);
01892 
01893        if (errflag)
01894        {
01895               maildir_deletenewmsg(newdraftfd, INBOX "." DRAFTS, draftfilename);
01896        }
01897        else if (maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, 1,
01898                               prev_size))
01899        {
01900               printf("%s", getarg("QUOTAERR"));
01901        }
01902 
01903        free(draftfilename);
01904 }
01905 
01906 /* Split apart date/time string into space-separated words */
01907 
01908 static char **mkargv(char *p, int *argc)
01909 {
01910        int pass;
01911        char **argv=0;
01912        char *q;
01913 
01914        /* Two passes - count words, then make them */
01915 
01916        for (pass=0; pass<2; pass++)
01917        {
01918               if (pass)
01919               {
01920                      if ((argv=malloc(sizeof(char *)* (*argc+1))) == NULL)
01921                             return (NULL);
01922               }
01923               *argc=0;
01924 
01925               for (q=p; *q; )
01926               {
01927                      if (isspace((int)(unsigned char)*q))
01928                      {
01929                             ++q;
01930                             continue;     /* Skip leading space */
01931                      }
01932 
01933                      if (pass)
01934                             argv[ *argc ] = q;
01935                      ++*argc;
01936 
01937                      while (*q)    /* Look for next space */
01938                      {
01939                             if (isspace((int)(unsigned char)*q))
01940                             {
01941                                    if (pass)
01942                                           *q=0;
01943                                    ++q;
01944                                    break;
01945                             }
01946                             ++q;
01947                      }
01948               }
01949        }
01950        argv[ *argc ] = 0;
01951        return (argv);
01952 }
01953 
01954 static int savetime(time_t, time_t, void *);
01955 
01956 static int addtime(int newdraftfd)
01957 {
01958        struct pcp_parse_datetime_info pdi;
01959        char *t_buf;
01960        char **t_argv;
01961        time_t starttime, endtime;
01962        int argn, argc;
01963        int h, m;
01964 
01965        pdi.today_name=cgi("today");              /* Locale string */
01966        pdi.tomorrow_name=cgi("tomorrow"); /* Locale string */
01967 
01968        t_buf=strdup(cgi("starttime"));
01969        if (!t_buf)
01970               return (-1);
01971        t_argv=mkargv(t_buf, &argc);
01972        if (!t_argv)
01973        {
01974               free(t_buf);
01975               return (-1);
01976        }
01977 
01978        argn=0;
01979        starttime=pcp_parse_datetime(&argn, argc, t_argv, &pdi);
01980        free(t_argv);
01981        free(t_buf);
01982        if (!starttime)
01983               return (-1);
01984        h=atoi(cgi("hours"));
01985        m=atoi(cgi("mins"));
01986        if (h < 0 || m < 0 || h > 999 || m > 59)
01987               return (-1);
01988 
01989        endtime=starttime + h * 60 * 60 + m * 60;
01990 
01991        argn=0;
01992        t_buf=strdup(cgi("endtime"));
01993        if (!t_buf)
01994               return (-1);
01995        t_argv=mkargv(t_buf, &argc);
01996        if (!t_argv)
01997        {
01998               free(t_buf);
01999               return (-1);
02000        }
02001 
02002        if (argc == 0)       /* Not a weekly event */
02003        {
02004               savetime(starttime, endtime, &newdraftfd);
02005        }
02006        else
02007        {
02008               if (pcp_parse_datetime_until(starttime, endtime, &argn, argc,
02009                                         t_argv,
02010                                         atoi(cgi("recurring")),
02011                                         savetime, &newdraftfd))
02012               {
02013                      free(t_argv);
02014                      free(t_buf);
02015                      return (-1);
02016               }
02017        }
02018        free(t_argv);
02019        free(t_buf);
02020        return (0);
02021 }
02022 
02023 static int savetime(time_t from, time_t to, void *dummy)
02024 {
02025        char buf[NUMBUFSIZE];
02026        int fd= *(int *)dummy;
02027 
02028        maildir_writemsgstr(fd, "X-Event-Time: ");
02029        maildir_writemsgstr(fd, libmail_str_time_t(from, buf));
02030        maildir_writemsgstr(fd, " ");
02031        maildir_writemsgstr(fd, libmail_str_time_t(to, buf));
02032        maildir_writemsgstr(fd, "\n");
02033        return (0);
02034 }
02035 
02036 static void addparticipant(int fd, const char *n)
02037 {
02038        char *nn, *p, *q;
02039 
02040        const char *domain;
02041 
02042        domain=getenv("AUTHADDR");
02043 
02044        if (domain)
02045               domain=strrchr(domain, '@');
02046 
02047        if (domain)
02048               ++domain;
02049        else
02050               domain=myhostname();
02051 
02052        while (n && isspace((int)(unsigned char)*n))
02053               ++n;
02054 
02055        if (!n || !*n)
02056               return;
02057 
02058        if (strchr(n, '\n') || strchr(n, '\r'))
02059               return;
02060 
02061        if ((nn=malloc(strlen(n)+strlen(domain)+2)) == NULL)
02062               enomem();
02063 
02064        strcpy(nn, n);
02065 
02066        for (p=q=nn; *p; p++)
02067               if (!isspace((int)(unsigned char)*p))
02068                      q=p+1;
02069        *q=0;
02070 
02071        if (strchr(nn, '@') == 0)
02072               strcat(strcat(nn, "@"), domain);
02073 
02074 
02075        maildir_writemsgstr(fd, "X-Event-Participant: ");
02076        maildir_writemsgstr(fd, nn);
02077        maildir_writemsgstr(fd, "\n");
02078        add_my_participant(nn);
02079        free(nn);
02080 }
02081 
02082 /* ------------- Save text ------------- */
02083 
02084 static char *savedraft()
02085 {
02086        const char *p=cgi("draftmessage");
02087        char *msg, *filename;
02088 
02089        if (p && *p)
02090        {
02091               CHECKFILENAME(p);
02092        }
02093 
02094        filename=p && *p ? maildir_find(INBOX "." DRAFTS, p):NULL;
02095 
02096        msg=newmsg_createdraft_do(filename, cgi("message"), NEWMSG_PCP);
02097        if (filename)
02098               free(filename);
02099 
02100        if (!msg)
02101               enomem();
02102        return (msg);
02103 }
02104 
02105 static void previewdraft(char *msg, void (*func)(const char *))
02106 {
02107        char *msg2, *msg2p;
02108 
02109        msg2=maildir_find(INBOX "." DRAFTS, msg);
02110        free(msg);
02111        if (!msg2)
02112               enomem();
02113        if ((msg2p=strrchr(msg2, '/')) != 0)
02114               ++msg2p;
02115        else
02116               msg2p=msg2;
02117 
02118        cgi_put("draftmessage", msg2p);
02119        if (func)
02120               (*func)(msg2p);
02121        output_form("newevent.html");
02122        free(msg2);
02123 }
02124 
02125 void sqpcp_preview()
02126 {
02127        char *msg;
02128 
02129        msg=savedraft();
02130        previewdraft(msg, NULL);
02131 }
02132 
02133 void sqpcp_postpone()
02134 {
02135        char *msg;
02136 
02137        msg=savedraft();
02138        free(msg);
02139        output_form("folders.html");
02140 }
02141 
02142 static void deleteattach(const char *);
02143 
02144 void sqpcp_deleteattach()
02145 {
02146        char *msg;
02147 
02148        msg=savedraft();
02149        previewdraft(msg, deleteattach);
02150 }
02151 
02152 static void deleteattach(const char *msg)
02153 {
02154        attach_delete(msg);
02155 }
02156 
02157 static void doupload(const char *);
02158 
02159 void sqpcp_uploadattach()
02160 {
02161        char *msg;
02162 
02163        msg=savedraft();
02164        previewdraft(msg, doupload);
02165 }
02166 
02167 static void doupload(const char *msg)
02168 {
02169        int flag;
02170 
02171        flag=attach_upload(msg, NULL, NULL);
02172 
02173        if (flag)
02174               cgi_put("error", "quota");
02175 }
02176 
02177 
02178 void sqpcp_attachpubkey()
02179 {
02180        char *msg;
02181 
02182        msg=savedraft();
02183        previewdraft(msg, NULL);
02184 }
02185 
02186 void sqpcp_attachprivkey()
02187 {
02188        char *msg;
02189 
02190        msg=savedraft();
02191        previewdraft(msg, NULL);
02192 }
02193 
02194 /* ---------------- Save event ------------------ */
02195 
02196 struct participant_list {
02197        struct participant_list *next;
02198        char *address;
02199 } ;
02200 
02201 struct saveinfo {
02202        struct PCP_event_time *times;
02203        unsigned n_times;
02204        struct PCP_event_participant *participants;
02205        unsigned n_participants;
02206        struct participant_list *participant_list;
02207 
02208        char *old_eventid;
02209 } ;
02210 
02211 static int init_saveinfo(struct saveinfo *si, FILE *fp)
02212 {
02213        struct rfc822hdr h;
02214 
02215        struct savetimelist {
02216               struct savetimelist *next;
02217               struct PCP_event_time event_time;
02218        } *tlist=NULL, *p;
02219        unsigned tcnt=0;
02220        struct participant_list *l;
02221 
02222 
02223        si->times=NULL;
02224        si->n_times=0;
02225        si->old_eventid=0;
02226        si->participants=NULL;
02227        si->n_participants=0;
02228        si->participant_list=NULL;
02229 
02230        rfc822hdr_init(&h, BUFSIZ);
02231        while (rfc822hdr_read(&h, fp, NULL, 0) == 0)
02232        {
02233               unsigned long a, b;
02234 
02235               if (strcasecmp(h.header, "X-Event-Participant") == 0 && h.value)
02236               {
02237                      l=malloc(sizeof(struct participant_list));
02238                      if (!l || (l->address=strdup(h.value)) == NULL)
02239                      {
02240                             if (l)
02241                                    free(l);
02242 
02243                             while ((l=si->participant_list) != NULL)
02244                             {
02245                                    si->participant_list=l->next;
02246                                    free(l->address);
02247                                    free(l);
02248                             }
02249                             while (tlist)
02250                             {
02251                                    p=tlist;
02252                                    tlist=p->next;
02253                                    free(p);
02254                             }
02255                             rfc822hdr_free(&h);
02256                             return (-1);
02257                      }
02258                      l->next=si->participant_list;
02259                      si->participant_list=l;
02260                      ++si->n_participants;
02261               }
02262               else if (strcasecmp(h.header, "X-Event-Time") == 0 &&
02263                       h.value && sscanf(h.value, "%lu %lu", &a, &b) == 2)
02264               {
02265                      if ((p=malloc(sizeof(struct savetimelist))) == NULL)
02266                      {
02267                             while ((l=si->participant_list) != NULL)
02268                             {
02269                                    si->participant_list=l->next;
02270                                    free(l->address);
02271                                    free(l);
02272                             }
02273                             while (tlist)
02274                             {
02275                                    p=tlist;
02276                                    tlist=p->next;
02277                                    free(p);
02278                             }
02279                             rfc822hdr_free(&h);
02280                             return (-1);
02281                      }
02282                      p->next=tlist;
02283                      tlist=p;
02284                      p->event_time.start=a;
02285                      p->event_time.end=b;
02286                      ++tcnt;
02287               }
02288 
02289               if (strcasecmp(h.header, "X-Old-EventId") == 0 && h.value)
02290               {
02291                      if (si->old_eventid)
02292                             free(si->old_eventid);
02293                      si->old_eventid=strdup(h.value);
02294                      if (!si->old_eventid)
02295                      {
02296                             rfc822hdr_free(&h);
02297                             return (-1);
02298                      }
02299               }
02300        }
02301        rfc822hdr_free(&h);
02302 
02303        if (si->n_participants)
02304        {
02305               unsigned n=0;
02306 
02307               if ((si->participants
02308                    =calloc(sizeof(struct PCP_event_participant),
02309                           si->n_participants)) == NULL)
02310               {
02311                      while ((l=si->participant_list) != NULL)
02312                      {
02313                             si->participant_list=l->next;
02314                             free(l->address);
02315                             free(l);
02316                      }
02317                      while (tlist)
02318                      {
02319                             p=tlist;
02320                             tlist=p->next;
02321                             free(p);
02322                      }
02323                      return (-1);
02324               }
02325 
02326               for (l=si->participant_list; l; l=l->next)
02327               {
02328                      si->participants[n].address=l->address;
02329                      ++n;
02330               }
02331        }
02332 
02333        if (tcnt)
02334        {
02335               si->n_times=tcnt;
02336               if ((si->times=malloc(sizeof(struct PCP_event_time)
02337                                   *tcnt)) == NULL)
02338               {
02339                      while ((l=si->participant_list) != NULL)
02340                      {
02341                             si->participant_list=l->next;
02342                             free(l->address);
02343                             free(l);
02344                      }
02345                      while (tlist)
02346                      {
02347                             p=tlist;
02348                             tlist=p->next;
02349                             free(p);
02350                      }
02351                      if (si->old_eventid)
02352                             free(si->old_eventid);
02353                      return (-1);
02354               }
02355               tcnt=0;
02356               while (tlist)
02357               {
02358                      p=tlist;
02359                      tlist=p->next;
02360                      si->times[tcnt]=p->event_time;
02361                      free(p);
02362                      ++tcnt;
02363               }
02364        }
02365        return (0);
02366 }
02367 
02368 static void free_saveinfo(struct saveinfo *si)
02369 {
02370        struct participant_list *l;
02371 
02372        if (si->participants)
02373               free(si->participants);
02374 
02375        while ((l=si->participant_list) != NULL)
02376        {
02377               si->participant_list=l->next;
02378               free(l->address);
02379               free(l);
02380        }
02381 
02382        if (si->times)
02383               free(si->times);
02384        if (si->old_eventid)
02385               free(si->old_eventid);
02386 }
02387 
02388 static void dropquota(const char *filename, int fd)
02389 {
02390        unsigned long filesize=0;
02391 
02392        if (maildir_parsequota(filename, &filesize))
02393        {
02394               struct stat stat_buf;
02395 
02396               if (fstat(fd, &stat_buf))
02397                      stat_buf.st_size=0;
02398               filesize=stat_buf.st_size;
02399        }
02400 
02401        maildir_quota_deleted(".", (int64_t)-filesize, -1);
02402 }
02403 
02404 /* ------------------------------------------------------------------------
02405 **
02406 ** Save a calendar event
02407 ** ----------------------------------------------------------------------*/
02408 
02409 static int dosave(FILE *, struct saveinfo *);
02410 
02411 void sqpcp_save()
02412 {
02413        char *msg, *sentmsg, *p;
02414        FILE *fp;
02415        struct saveinfo si;
02416        int isgpgerr;
02417 
02418        msg=savedraft();
02419        if (*cgi("error"))   /* Error, go back to the screen */
02420        {
02421               previewdraft(msg, NULL);
02422               return;
02423        }
02424 
02425        fp=openoldfp(msg, NULL);
02426        if (!fp)
02427        {
02428               free(msg);
02429               enomem();
02430        }
02431 
02432        if (init_saveinfo(&si, fp))
02433        {
02434               fclose(fp);
02435               free(msg);
02436               enomem();
02437        }
02438 
02439        if (si.times == 0)
02440        {
02441               fclose(fp);
02442               cgi_put("error", "time");
02443               previewdraft(msg, NULL);
02444               return;
02445        }
02446        fclose(fp);
02447 
02448        sentmsg=newmsg_createsentmsg(msg, &isgpgerr);
02449 
02450        /* Immediately remove the formatted event text from the sent folder */
02451 
02452        if (sentmsg)
02453        {
02454               p=maildir_find(INBOX "." SENT, sentmsg);
02455               free(sentmsg);
02456               sentmsg=p;
02457        }
02458 
02459        if (!sentmsg)
02460        {
02461               cgi_put("error", "quota");  /* TODO: gpgerr */
02462               free_saveinfo(&si);
02463               previewdraft(msg, NULL);
02464               return;
02465        }
02466 
02467 
02468        fp=fopen(sentmsg, "r");
02469        if (!fp)
02470        {
02471               free(sentmsg);
02472               free(msg);
02473               free_saveinfo(&si);
02474               enomem();
02475               return;
02476        }
02477 
02478        fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
02479 
02480        unlink(sentmsg);
02481        dropquota(sentmsg, fileno(fp));
02482        free(sentmsg);
02483 
02484        if (dosave(fp, &si))
02485        {
02486               fclose(fp);
02487               free_saveinfo(&si);
02488               previewdraft(msg, NULL);
02489               return;
02490        }
02491        fclose(fp);
02492 
02493        p=maildir_find(INBOX "." DRAFTS, msg);
02494        free(msg);
02495 
02496        fp=p ? fopen(p, "r"):NULL;
02497        unlink(p);
02498        if (fp)
02499        {
02500               dropquota(p, fileno(fp));
02501               fclose(fp);
02502        }
02503        free(p);
02504        free_saveinfo(&si);
02505        output_form("folders.html");
02506 }
02507 
02508 /* With all the preliminaries out of the way, put it on the calendar */
02509 
02510 static void saveerror(struct PCP *pcp, const int *xerror)
02511 {
02512        static char *errmsgbuf=0;
02513        const char *p;
02514 
02515        if (xerror)
02516               switch (*xerror) {
02517               case PCP_ERR_SYSERR: /* Can be deliberate, see addacl() */
02518                      cgi_put("error", "calendar");
02519                      cgi_put("pcperror", strerror(errno));
02520                      return;
02521               case PCP_ERR_LOCK:
02522                      cgi_put("error", "locked");
02523                      return;
02524               case PCP_ERR_CONFLICT:
02525                      cgi_put("error", "conflict");
02526                      return;
02527               case PCP_ERR_EVENTNOTFOUND:
02528                      cgi_put("error", "notfound");
02529                      return;
02530               case PCP_ERR_EVENTLOCKED:
02531                      cgi_put("error", "eventlocked");
02532                      return;
02533               }
02534 
02535        cgi_put("error", "calendar");
02536 
02537        if (errmsgbuf)
02538               free(errmsgbuf);
02539 
02540        /*
02541        ** Save err msg into a static buffer, because err msg text memory
02542        ** may go away after the handle is closed.
02543        */
02544 
02545        p=pcp_errmsg(pcp);
02546        errmsgbuf=strdup(p ? p:"");
02547        cgi_put("pcperror", errmsgbuf);
02548 }
02549 
02550 struct proxy_list_entry {
02551        struct proxy_list_entry *next;
02552        char *userid;
02553 } ;
02554 
02555 struct proxy_update_list {
02556        struct proxy_list_entry *new_list;
02557        struct proxy_list_entry *delete_list;
02558 } ;
02559 
02560 static void proxy_update_list_save(const char *action,
02561                                const char *userid,
02562                                void *voidarg)
02563 {
02564        struct proxy_update_list *pul=(struct proxy_update_list *)voidarg;
02565 
02566        struct proxy_list_entry **eptr, *e;
02567 
02568        if (strcmp(action, "NEW") == 0)
02569               eptr= &pul->new_list;
02570        else if (strcmp(action, "DELETE") == 0)
02571               eptr= &pul->delete_list;
02572        else
02573               return;
02574 
02575        while (*eptr && strcmp( (*eptr)->userid, userid) == 0)
02576               eptr= &(*eptr)->next;
02577 
02578        if ((e=malloc(sizeof(struct proxy_list_entry))) == NULL ||
02579            (e->userid=strdup(userid)) == NULL)
02580        {
02581               if (e)
02582                      free(e);
02583               fprintf(stderr, "CRIT: out of memory.\n");
02584               return;
02585        }
02586 
02587        e->next= *eptr;
02588        *eptr=e;
02589 }
02590 
02591 static void proxy_update_list_free(struct proxy_update_list *p)
02592 {
02593        struct proxy_list_entry *e;
02594 
02595        while ((e=p->new_list) != NULL)
02596        {
02597               p->new_list=e->next;
02598               free(e->userid);
02599               free(e);
02600        }
02601 
02602        while ((e=p->delete_list) != NULL)
02603        {
02604               p->delete_list=e->next;
02605               free(e->userid);
02606               free(e);
02607        }
02608 }
02609 
02610 static void proxy_notify_email_msg(FILE *, struct proxy_list_entry *,
02611                                const char *,
02612                                const struct PCP_event_time *,
02613                                unsigned);
02614 
02615 static void proxy_notify_email(FILE *f, struct proxy_update_list *pul,
02616                             const struct PCP_event_time *t,
02617                             unsigned tn)
02618 {
02619        proxy_notify_email_msg(f, pul->new_list, "eventnotifynew.txt",
02620                             t, tn);
02621        proxy_notify_email_msg(f, pul->delete_list, "eventnotifydelete.txt",
02622                             NULL, 0);
02623 }
02624 
02625 static void dosendnotice(FILE *, FILE *, FILE *, struct proxy_list_entry *,
02626                       const char *, const struct PCP_event_time *,
02627                       unsigned);
02628 
02629 static void proxy_notify_email_msg(FILE *f, struct proxy_list_entry *l,
02630                                const char *template,
02631                                const struct PCP_event_time *t,
02632                                unsigned tn)
02633 {
02634        FILE *tmpfp;
02635        pid_t p, p2;
02636        int waitstat;
02637        int pipefd[2];
02638        FILE *tofp;
02639        const char *returnaddr=login_returnaddr();
02640        char subjectlabel[100];
02641 
02642        if (!l)
02643               return;
02644 
02645        if (fseek(f, 0L, SEEK_SET) < 0
02646            || lseek(fileno(f), 0L, SEEK_SET) < 0)
02647        {
02648               fprintf(stderr, "CRIT: seek failed: %s\n", strerror(errno));
02649               return;
02650        }
02651 
02652        subjectlabel[0]=0;
02653 
02654        if ((tmpfp=open_langform(sqwebmail_content_language,
02655                              "eventnotifysubject.txt", 0)) != NULL)
02656        {
02657               if (fgets(subjectlabel, sizeof(subjectlabel), tmpfp) == NULL)
02658                      subjectlabel[0]=0;
02659               else
02660               {
02661                      char *p=strchr(subjectlabel, '\n');
02662 
02663                      if (p) *p=0;
02664               }
02665               fclose(tmpfp);
02666        }
02667        if (subjectlabel[0] == 0)
02668               strcpy(subjectlabel, "[calendar]");
02669 
02670        if ((tmpfp=open_langform(sqwebmail_content_language, template, 0))
02671            == NULL)
02672        {
02673               fprintf(stderr, "CRIT: %s: %s\n", template, strerror(errno));
02674               return;
02675        }
02676 
02677        signal(SIGPIPE, SIG_IGN);
02678 
02679        if (pipe(pipefd) < 0)
02680        {
02681               fclose(tmpfp);
02682               fprintf(stderr, "CRIT: pipe: %s\n", strerror(errno));
02683               return;
02684        }
02685 
02686        p=fork();
02687 
02688        if (p < 0)
02689        {
02690               close(pipefd[0]);
02691               close(pipefd[1]);
02692               fclose(tmpfp);
02693               fprintf(stderr, "CRIT: fork: %s\n", strerror(errno));
02694               return;
02695        }
02696 
02697        if (p == 0)
02698        {
02699               dup2(pipefd[0], 0);
02700               close(pipefd[0]);
02701               close(pipefd[1]);
02702               execl(SENDITSH, "sendit.sh", returnaddr,
02703                                 sqwebmail_mailboxid, NULL);
02704               fprintf(stderr, "CRIT: exec " SENDITSH ": %s\n", strerror(errno));
02705               exit(1);
02706        }
02707        close(pipefd[0]);
02708        if ((tofp=fdopen(pipefd[1], "w")) == NULL)
02709        {
02710               fprintf(stderr, "CRIT: exec " SENDITSH ": %s\n", strerror(errno));
02711        }
02712        else
02713        {
02714               dosendnotice(tofp, tmpfp, f, l, subjectlabel, t, tn);
02715        }
02716        fclose(tofp);
02717        close(pipefd[1]);
02718        fclose(tmpfp);
02719 
02720        waitstat=256;
02721        while ((p2=wait(&waitstat)) != p && p2 >= 0)
02722               ;
02723 
02724        if (!WIFEXITED(waitstat) || WEXITSTATUS(waitstat))
02725               fprintf(stderr, "CRIT: event notify mail failed\n");
02726 }
02727 
02728 /*
02729 ** Ok, the preliminaries are out of the way, now spit it out.
02730 */
02731 
02732 static void dosendnotice(FILE *tofp,      /* Pipe to sendit.sh */
02733                       FILE *tmpfp, /*
02734                                    ** Template file with MIME headers and
02735                                    ** canned verbiage
02736                                    */
02737                       FILE *eventfp,      /* Original event */
02738                       struct proxy_list_entry *idlist,
02739                       const char *subjectlabel,
02740                       const struct PCP_event_time *time_list,
02741                       unsigned n_time_list)
02742 {
02743        struct rfc822hdr h;
02744        const char *p;
02745        int c;
02746        unsigned u;
02747 
02748        rfc822hdr_init(&h, 8192);
02749 
02750        while (rfc822hdr_read(&h, eventfp, NULL, 0) == 0)
02751        {
02752               if (strcasecmp(h.header, "From") == 0 ||
02753                   strcasecmp(h.header, "Date") == 0)
02754               {
02755                      fprintf(tofp, "%s: %s\n", h.header,
02756                             h.value ? h.value:"");
02757               }
02758               else if (strcasecmp(h.header, "Subject") == 0)
02759               {
02760                      fprintf(tofp, "%s: %s %s\n", h.header,
02761                             subjectlabel,
02762                             h.value ? h.value:"");
02763               }
02764        }
02765        rfc822hdr_free(&h);
02766 
02767        p="To: ";
02768 
02769        while (idlist)
02770        {
02771               fprintf(tofp, "%s%s", p, idlist->userid);
02772               p=",\n  ";
02773               idlist=idlist->next;
02774        }
02775        fprintf(tofp, "\n");
02776 
02777        while ((c=getc(tmpfp)) != EOF)
02778               putc(c, tofp);
02779 
02780        for (u=0; u<n_time_list; u++)
02781        {
02782               char buffer[200];
02783 
02784               if (pcp_fmttimerange(buffer, sizeof(buffer),
02785                                  time_list[u].start,
02786                                  time_list[u].end) == 0)
02787               {
02788                      fprintf(tofp, "     %s\n", buffer);
02789               }
02790        }
02791 }
02792 
02793 static int dosave(FILE *fp, struct saveinfo *si)
02794 {
02795        struct PCP *pcp=sqpcp_calendar();
02796        struct PCP_save_event se;
02797        struct PCP_new_eventid *nei;
02798        struct PCP_commit c;
02799 
02800        struct proxy_update_list pul;
02801 
02802        if (!pcp)
02803        {
02804               cgi_put("error", "calendar");      /* TODO: actual error */
02805               cgi_put("pcperror", "");
02806               return (-1);
02807        }
02808 
02809        memset(&se, 0, sizeof(se));
02810        se.write_event_fd=fileno(fp);
02811        se.event_participants=si->participants;
02812        se.n_event_participants=si->n_participants;
02813 
02814        if (*cgi("okconflict"))
02815               se.flags |= PCP_OK_CONFLICT;
02816        if (*cgi("okerrors"))
02817               se.flags |= PCP_OK_PROXY_ERRORS;
02818 
02819        nei=pcp_new_eventid(pcp, si->old_eventid, &se);
02820        if (!nei)
02821        {
02822               saveerror(pcp, NULL);
02823               return (-1);
02824        }
02825 
02826        memset(&c, 0, sizeof(c));
02827        c.event_times=si->times;
02828        c.n_event_times=si->n_times;
02829        c.flags=se.flags;
02830 
02831        init_save_conflict();
02832        c.add_conflict_callback=save_conflict;
02833 
02834        memset(&pul, 0, sizeof(pul));
02835 
02836        c.proxy_callback= &proxy_update_list_save;
02837        c.proxy_callback_ptr= &pul;
02838 
02839        if (pcp_commit(pcp, nei, &c))
02840        {
02841               proxy_update_list_free(&pul);
02842               saveerror(pcp, &c.errcode);
02843               pcp_destroy_eventid(pcp, nei);
02844               return (-1);
02845        }
02846        pcp_destroy_eventid(pcp, nei);
02847        unlink(CACHE);       /* Have it rebuilt */
02848        proxy_notify_email(fp, &pul, c.event_times, c.n_event_times);
02849        proxy_update_list_free(&pul);
02850        refreshcache(pcp);
02851        return (0);
02852 }
02853 
02854 /* -------------- Daily stuff --------------- */
02855 
02856 void sqpcp_todays_date()
02857 {
02858        unsigned y, m, d;
02859        time_t start;
02860        time_t end;
02861        char buf[100];
02862 
02863        if (sscanf(cgi("date"), "%4u%2u%2u", &y, &m, &d) != 3
02864            || pcp_parse_ymd(y, m, d, &start, &end)
02865            || pcp_fmttime(buf, sizeof(buf), start, FMTTIME_DATE))
02866               return;
02867 
02868        print_safe(buf);
02869 }
02870 
02871 void sqpcp_todays_date_verbose()
02872 {
02873        unsigned y, m, d;
02874        time_t start;
02875        time_t end;
02876        char buf[500];
02877        struct tm *tmptr;
02878 
02879        if (sscanf(cgi("date"), "%4u%2u%2u", &y, &m, &d) != 3
02880            || pcp_parse_ymd(y, m, d, &start, &end)
02881            || (tmptr=localtime(&start)) == NULL
02882            || strftime(buf, sizeof(buf), getarg("DATEFORMAT"), tmptr) == 0)
02883               return;
02884 
02885        print_safe(buf);
02886 }
02887 
02888 void sqpcp_weeklylink()
02889 {
02890        output_scriptptrget();
02891        printf("&amp;form=eventweekly&amp;weekof=%s", cgi("date"));
02892 }
02893 
02894 void sqpcp_monthlylink()
02895 {
02896        const char *p=cgi("date");
02897 
02898        if (!*p)
02899               p=cgi("weekof");
02900        output_scriptptrget();
02901        printf("&amp;form=eventmonthly&amp;monthof=%s", p);
02902 }
02903 
02904 #define VIEW_DAILY   0
02905 #define       VIEW_WEEKLY   1
02906 #define VIEW_MONTHLY 2
02907 
02908 static void do_daily_view(struct cacherecord *, unsigned, int,
02909                        time_t *, time_t *);
02910 
02911 static void show_pcp_errmsg(const char *p)
02912 {
02913        printf("<pre class=\"error\">");
02914        output_attrencoded_oknl_fp(p, stdout);
02915        printf("</pre>");
02916 }
02917 
02918 void sqpcp_daily_view()
02919 {
02920        unsigned y, m, d;
02921        time_t start;
02922        time_t end;
02923 
02924        struct PCP *pcp;
02925        struct cacherecord *recs;
02926        unsigned n_recs;
02927 
02928        if (*cgi("clearcache"))
02929               unlink(CACHE);
02930 
02931        if (sscanf(cgi("date"), "%4u%2u%2u", &y, &m, &d) != 3
02932            || pcp_parse_ymd(y, m, d, &start, &end))
02933               return;
02934 
02935        if ((pcp=sqpcp_calendar()) == NULL)
02936        {
02937               printf("<span class=\"error\">%s</span>", strerror(errno));
02938               return;
02939        }
02940 
02941        if (createcache(pcp, &recs, &n_recs, start, end))
02942        {
02943               show_pcp_errmsg(pcp_errmsg(pcp));
02944               return;
02945        }
02946 
02947        (void)do_daily_view(recs, n_recs, VIEW_DAILY, NULL, NULL);
02948        destroycache(recs, n_recs);
02949 }
02950 
02951 static void print_event_link_url(const char *id, const char *extra)
02952 {
02953        output_scriptptrget();
02954        printf("%s&amp;form=eventshow&amp;eventid=", extra);
02955        output_urlencoded(id);
02956        if (*cgi("date"))
02957               printf("&amp;date=%s", cgi("date"));
02958        if (*cgi("weekof"))
02959               printf("&amp;weekof=%s", cgi("weekof"));
02960        if (*cgi("monthof"))
02961               printf("&amp;monthof=%s", cgi("monthof"));
02962 }
02963 
02964 static void print_event_link(const char *id, const char *extra,
02965                           const char *extra2)
02966 {
02967        printf("<a href=\"");
02968        print_event_link_url(id, extra);
02969        printf("\" %s >", extra2);
02970 }
02971 
02972 static void do_daily_view(struct cacherecord *recs, unsigned n_recs,
02973                        int viewtype, time_t *start_ptr, time_t *end_ptr)
02974 {
02975        unsigned i;
02976        int printed=0;
02977 
02978        printf("<table width=\"100%%\">");
02979 
02980        for (i=0; i<n_recs; i++)
02981        {
02982               char date1[256];
02983               char date2[256];
02984 
02985               char time1[128];
02986               char time2[128];
02987 
02988               time_t start=recs[i].start;
02989               time_t end=recs[i].end;
02990 
02991               if (start_ptr && *start_ptr >= end)
02992                      continue;
02993 
02994               if (end_ptr && *end_ptr <= start)
02995                      continue;
02996 
02997               if ( start_ptr && *start_ptr > start)
02998                      start= *start_ptr;
02999 
03000               if ( end_ptr && *end_ptr < end)
03001                      end= *end_ptr;
03002 
03003               if (pcp_fmttime(date1, sizeof(date1),
03004                             start, FMTTIME_DATE))
03005                      continue;
03006               if (pcp_fmttime(date2, sizeof(date2),
03007                             end, FMTTIME_DATE))
03008                             continue;
03009 
03010               printed=1;
03011 
03012               if (strcmp(date1, date2) && viewtype == VIEW_DAILY)
03013               {
03014                      char timerange[512];
03015 
03016                      if (pcp_fmttimerange(timerange, sizeof(timerange),
03017                                         start, end))
03018                             continue;
03019 
03020                      printf("<tr><td align=\"left\">");
03021                      print_event_link(recs[i].eventid, "", "class=\"dailyeventtimes\"");
03022                      print_safe(timerange);
03023               }
03024               else
03025               {
03026                      if (pcp_fmttime(time1, sizeof(time1),
03027                                    start,
03028                                    FMTTIME_TIME))
03029                             continue;
03030 
03031                      if (pcp_fmttime(time2,
03032                                    sizeof(time2),
03033                                    end,
03034                                    FMTTIME_TIME))
03035                             continue;
03036 
03037                      printf("<tr><td align=\"left\">");
03038                      print_event_link(recs[i].eventid, "", "class=\"dailyeventtimes\"");
03039                      print_safe(time1);
03040                      printf("&nbsp;-&nbsp;");
03041                      print_safe(time2);
03042               }
03043               printf("</a>");
03044 
03045               if (viewtype == VIEW_DAILY)
03046               {
03047                      printf("</td><td width=\"100%%\">");
03048               }
03049               else
03050                      printf("<br />");
03051 
03052               printf("&nbsp;&nbsp;");
03053               print_event_link(recs[i].eventid, "", "class=\"dailyeventsubject\"");
03054               print_event_subject(recs[i].flags, recs[i].subject,
03055                                 viewtype == VIEW_DAILY ? 80:15);
03056               printf("</a>");
03057               if (viewtype != VIEW_DAILY)
03058                      printf("<br />&nbsp;");
03059 
03060               printf("</td></tr>\n");
03061        }
03062 
03063        if (!printed)
03064        {
03065               printf("<tr><td align=\"center\">%s</td></tr>",
03066                      getarg("NOEVENTS"));
03067        }
03068 
03069        printf("</table>\n");
03070 }
03071 
03072 void sqpcp_prevday()
03073 {
03074        unsigned y, m, d;
03075        time_t start;
03076        time_t end;
03077        struct tm *tm;
03078        char buf[256];
03079 
03080        if (sscanf(cgi("date"), "%4u%2u%2u", &y, &m, &d) != 3
03081            || pcp_parse_ymd(y, m, d, &start, &end))
03082               return;
03083 
03084        start -= 12 * 60 * 60;
03085 
03086        if ((tm=localtime(&start)) == NULL)
03087               return;
03088 
03089        y=tm->tm_year + 1900;
03090        m=tm->tm_mon + 1;
03091        d=tm->tm_mday;
03092 
03093        if (pcp_parse_ymd(y, m, d, &start, &end)
03094            || (tm=localtime(&start)) == NULL
03095            || strftime(buf, sizeof(buf), getarg("PREVDAY"), tm) == 0)
03096               return;
03097 
03098        printf("<a class=\"dailynextprev\" href=\"");
03099        output_scriptptrget();
03100        printf("&amp;form=eventdaily&amp;date=%04d%02d%02d\">%s</a>", y, m, d, buf);
03101 }
03102 
03103 void sqpcp_nextday()
03104 {
03105        unsigned y, m, d;
03106        time_t start;
03107        time_t end;
03108        struct tm *tm;
03109        char buf[256];
03110 
03111        if (sscanf(cgi("date"), "%4u%2u%2u", &y, &m, &d) != 3
03112            || pcp_parse_ymd(y, m, d, &start, &end))
03113               return;
03114 
03115        start=end;
03116 
03117        if ((tm=localtime(&start)) == NULL)
03118               return;
03119 
03120        y=tm->tm_year + 1900;
03121        m=tm->tm_mon + 1;
03122        d=tm->tm_mday;
03123 
03124        if (pcp_parse_ymd(y, m, d, &start, &end)
03125            || (tm=localtime(&start)) == NULL
03126            || strftime(buf, sizeof(buf), getarg("NEXTDAY"), tm) == 0)
03127               return;
03128 
03129        printf("<a class=\"dailynextprev\" href=\"");
03130        output_scriptptrget();
03131        printf("&amp;form=eventdaily&amp;date=%04d%02d%02d\">%s</a>", y, m, d, buf);
03132 }
03133 
03134 /* -------------- Display event stuff --------------- */
03135 
03136 struct display_retr_time_list {
03137        struct display_retr_time_list *next;
03138        time_t start;
03139        time_t end;
03140 } ;
03141 
03142 struct display_retr_participant_list {
03143        struct display_retr_participant_list *next;
03144        char *participant;
03145 } ;
03146 
03147 struct display_retr {
03148        FILE *f;
03149        
03150        struct display_retr_time_list *time_list;
03151        struct display_retr_participant_list *participant_list;
03152 
03153 } ;
03154 
03155 static void free_display_retr(struct display_retr *r)
03156 {
03157 }
03158 
03159 
03160 static int save_displayed_event(struct PCP_retr *, const char *, int, void *);
03161 
03162 static int set_status(struct PCP_retr *, int, void *);
03163 
03164 void sqpcp_displayeventinit()
03165 {
03166        struct PCP *pcp;
03167        const char *event_id_list[2];
03168        struct PCP_retr r;
03169 
03170        showerror();
03171 
03172        pcp=sqpcp_calendar();
03173 
03174        if (!pcp)
03175               return;
03176 
03177        event_id_list[0]=cgi("eventid");
03178        event_id_list[1]=0;
03179 
03180        init_save_conflict();
03181        if (*cgi("docancel"))
03182        {
03183               if (pcp_cancel(pcp, event_id_list[0], NULL))
03184                      show_pcp_errmsg(pcp_errmsg(pcp));
03185               unlink(CACHE);
03186        }
03187 
03188        if (*cgi("douncancel"))
03189        {
03190               struct PCP_uncancel u;
03191               int flags=0;
03192 
03193               memset(&u, 0, sizeof(u));
03194 
03195               if (*cgi("okconflict"))
03196                      flags |= PCP_OK_CONFLICT;
03197 
03198               u.uncancel_conflict_callback=save_conflict;
03199               if (pcp_uncancel(pcp, event_id_list[0], flags, &u))
03200               {
03201                      saveerror(pcp, &u.errcode);
03202                      showerror();
03203                      if (u.errcode == PCP_ERR_CONFLICT)
03204                             cgi_put("okconflict", "1");
03205               }
03206               unlink(CACHE);
03207        }
03208 
03209        memset(&r, 0, sizeof(r));
03210        r.event_id_list=event_id_list;
03211        r.callback_retr_status=set_status;
03212 
03213        if (pcp_retr(pcp, &r))
03214        {
03215               show_pcp_errmsg(pcp_errmsg(pcp));
03216               return;
03217        }
03218 
03219 }
03220 
03221 static int set_status(struct PCP_retr *pcp, int status, void *dummy)
03222 {
03223        cgi_put("event_cancelled", status & LIST_CANCELLED ? "1":"");
03224        cgi_put("event_booked", status & LIST_BOOKED ? "1":"");
03225        cgi_put("event_proxy", status & LIST_PROXY ? "1":"");
03226        return (0);
03227 }
03228 
03229 static int save_displayed_date(struct PCP_retr *r, time_t start, time_t end,
03230                             void *vp)
03231 {
03232        struct display_retr *dr=(struct display_retr *)vp;
03233 
03234        struct display_retr_time_list **ptr, *p;
03235 
03236        for (ptr= &dr->time_list; *ptr; ptr=&(*ptr)->next)
03237               if ((*ptr)->start > start)
03238                      break;
03239 
03240        if ((p=malloc(sizeof(struct display_retr_time_list))) == NULL)
03241               return (-1);
03242 
03243        p->next= *ptr;
03244        *ptr=p;
03245        p->start=start;
03246        p->end=end;
03247 
03248        return (0);
03249 }
03250 
03251 static int save_displayed_participants(struct PCP_retr *r, const char *address,
03252                                    const char *dummy, void *vp)
03253 {
03254        struct display_retr *dr=(struct display_retr *)vp;
03255 
03256        struct display_retr_participant_list **ptr, *p;
03257 
03258        for (ptr= &dr->participant_list; *ptr; ptr=&(*ptr)->next)
03259               if (strcasecmp((*ptr)->participant, address) > 0)
03260                      break;
03261 
03262        if ((p=malloc(sizeof(struct display_retr_participant_list))) == NULL)
03263               return (-1);
03264 
03265        if ((p->participant=strdup(address)) == NULL)
03266        {
03267               free(p);
03268               return (-1);
03269        }
03270        p->next= *ptr;
03271        *ptr=p;
03272        return (0);
03273 }
03274 
03275 void sqpcp_displayevent()
03276 {
03277        struct PCP *pcp=sqpcp_calendar();
03278        const char *event_id_list[2];
03279        struct PCP_retr r;
03280        struct display_retr dr;
03281        struct maildir_tmpcreate_info createInfo;
03282        struct display_retr_time_list *tl;
03283        struct display_retr_participant_list *pl;
03284 
03285        if (!pcp)
03286               return;
03287 
03288        event_id_list[0]=cgi("eventid");
03289        event_id_list[1]=0;
03290 
03291        memset(&r, 0, sizeof(r));
03292        memset(&dr, 0, sizeof(dr));
03293        r.event_id_list=event_id_list;
03294        r.callback_arg=&dr;
03295        r.callback_rfc822_func=save_displayed_event;
03296        r.callback_retr_date=save_displayed_date;
03297        r.callback_retr_participants=save_displayed_participants;
03298 
03299        maildir_purgemimegpg(); /* Delete previous :calendar: file */
03300 
03301        maildir_tmpcreate_init(&createInfo);
03302        createInfo.uniq=":calendar:";
03303        createInfo.doordie=1;
03304 
03305        if ((dr.f=maildir_tmpcreate_fp(&createInfo)) == NULL)
03306        {
03307               error(strerror(errno));
03308        }
03309 
03310        cgi_put(MIMEGPGFILENAME, strrchr(createInfo.tmpname, '/')+1);
03311 
03312        if (pcp_retr(pcp, &r))
03313        {
03314               free_display_retr(&dr);
03315               fclose(dr.f);
03316               cgi_put(MIMEGPGFILENAME, "");
03317               unlink(createInfo.tmpname);
03318               maildir_tmpcreate_free(&createInfo);
03319               show_pcp_errmsg(pcp_errmsg(pcp));
03320               return;
03321        }
03322        fclose(dr.f);
03323 
03324        printf("<table class=\"calendarevent\" align=\"center\" border=\"0\"><tr valign=\"top\"><th align=\"left\">%s</th><td>",
03325               getarg("EVENT"));
03326 
03327        for (tl=dr.time_list; tl; tl=tl->next)
03328        {
03329               char buffer[512];
03330 
03331               if (pcp_fmttimerange(buffer, sizeof(buffer),
03332                                  tl->start, tl->end))
03333                      continue;
03334 
03335               printf("<span class=\"tt\">");
03336               print_safe(buffer);
03337               printf("</span><br />\n");
03338        }
03339        printf("</td></tr>\n");
03340 
03341        if (dr.participant_list)
03342        {
03343               printf("<tr valign=\"top\"><th align=\"left\">%s</th><td>",
03344                      getarg("PARTICIPANTS"));
03345               for (pl=dr.participant_list; pl; pl=pl->next)
03346               {
03347                      printf("<span class=\"tt\">&lt;");
03348                      print_safe(pl->participant);
03349                      printf("&gt;</span><br />\n");
03350               }
03351               printf("</td></tr>");
03352        }
03353        printf("</table>\n");
03354        folder_showmsg(INBOX "." DRAFTS, 0);
03355        free_display_retr(&dr);
03356        cgi_put(MIMEGPGFILENAME, "");
03357        maildir_tmpcreate_free(&createInfo);
03358 }
03359 
03360 static int save_displayed_event(struct PCP_retr *r,
03361                             const char *buf, int cnt,
03362                             void *vp)
03363 {
03364        if (fwrite( buf, cnt, 1, ((struct display_retr *)vp)->f) != 1)
03365               return (-1);
03366 
03367        return (0);
03368 }
03369 
03370 
03371 static void back_to_summary()
03372 {
03373        const char *p;
03374 
03375        if (*(p=cgi("monthof")) != 0)
03376        {
03377               printf("&amp;form=eventmonthly&amp;monthof=%s", p);
03378        }
03379        else if (*(p=cgi("weekof")) != 0)
03380        {
03381               printf("&amp;form=eventweekly&amp;weekof=%s", p);
03382        }
03383        else
03384        {
03385               p=cgi("date");
03386               printf("&amp;form=eventdaily&amp;date=%s", p);
03387        }
03388 }
03389 
03390 void sqpcp_eventbacklink()
03391 {
03392        output_scriptptrget();
03393        back_to_summary();
03394 }
03395 
03396 void sqpcp_eventeditlink()
03397 {
03398        const char *p=cgi("date");
03399 
03400        output_scriptptrget();
03401        printf("&amp;form=event-edit&amp;date=%s&amp;eventid=", p);
03402        output_urlencoded(cgi("eventid"));
03403 }
03404 
03405 void sqpcp_eventdeletelink()
03406 {
03407        const char *p=cgi("date");
03408 
03409        output_scriptptrget();
03410        printf("&amp;eventid=");
03411 
03412        output_urlencoded(cgi("eventid"));
03413        printf("&amp;form=eventdelete&amp;date=%s", p);
03414 }
03415 
03416 void sqpcp_eventcanceluncancellink()
03417 {
03418        print_event_link_url(cgi("eventid"), *cgi("event_cancelled")
03419                       ? (*cgi("okconflict") ?
03420                          "&amp;okconflict=1&amp;douncancel=1"
03421                          :"&amp;douncancel=1")
03422                           :"&amp;docancel=1");
03423 }
03424 
03425 void sqpcp_eventcanceluncancelimage()
03426 {
03427        printf("%s", getarg(*cgi("event_cancelled")
03428                          ? "UNCANCELIMAGE":"CANCELIMAGE"));
03429 }
03430 
03431 void sqpcp_eventcanceluncanceltext()
03432 {
03433        printf("%s", getarg(*cgi("event_cancelled")
03434                          ? "UNCANCELTEXT":"CANCELTEXT"));
03435 }
03436 
03437 void sqpcp_deleteeventinit()
03438 {
03439        sqpcp_displayeventinit();
03440        if (*cgi("event_proxy"))
03441               printf("%s", getarg("PROXYWARN"));
03442 }
03443 
03444 static int save_orig_headers(struct PCP_retr *pcp,
03445                           const char *h, const char *v, void *vp)
03446 {
03447        FILE *fp=(FILE *)vp;
03448 
03449        if (strcasecmp(h, "Date"))
03450               fprintf(fp, "%s: %s\n", h, v);
03451        return (0);
03452 }
03453 
03454 
03455 void sqpcp_dodelete()
03456 {
03457        struct PCP *pcp=sqpcp_calendar();
03458        struct PCP_retr r;
03459        const char *event_list_ary[2];
03460        struct PCP_delete del;
03461        struct proxy_update_list pul;
03462        FILE *tmpfp;
03463 
03464        if (!pcp)
03465               return;
03466 
03467        memset(&del, 0, sizeof(del));
03468        del.id=cgi("eventid");
03469 
03470        memset(&r, 0, sizeof(r));
03471        event_list_ary[0]=del.id;
03472        event_list_ary[1]=NULL;
03473        r.event_id_list=event_list_ary;
03474        r.callback_headers_func=save_orig_headers;
03475 
03476        tmpfp=tmpfile();
03477        if (!tmpfp)
03478               enomem();
03479        r.callback_arg=tmpfp;
03480        pcp_retr(pcp, &r);
03481 
03482        {
03483               time_t t;
03484 
03485               time(&t);
03486 
03487               fprintf(tmpfp, "Date: %s\n\n", rfc822_mkdate(t));
03488        }
03489 
03490        memset(&pul, 0, sizeof(pul));
03491        del.proxy_callback=&proxy_update_list_save;
03492        del.proxy_callback_ptr=&pul;
03493 
03494        if (pcp_delete(pcp, &del))
03495        {
03496               saveerror(pcp, &del.errcode);
03497               output_form("eventdelete.html");
03498        }
03499        else
03500        {
03501               proxy_notify_email(tmpfp, &pul, NULL, 0);
03502        }
03503        fclose(tmpfp);
03504        proxy_update_list_free(&pul);
03505        unlink(CACHE);
03506        output_form("eventdaily.html");
03507 }
03508 
03509 /* ------------- Bring in an event to edit -------------------------- */
03510 
03511 static int doeventedit(struct PCP *, int);
03512 
03513 int sqpcp_eventedit()
03514 {
03515        struct PCP *pcp=sqpcp_calendar();
03516        int newdraftfd;
03517        char *draftfilename;
03518 
03519        if (!pcp)
03520               return (-1);
03521 
03522        newdraftfd=maildir_createmsg(INBOX "." DRAFTS, 0, &draftfilename);
03523        if (doeventedit(pcp, newdraftfd))
03524        {
03525               maildir_deletenewmsg(newdraftfd, INBOX "." DRAFTS, draftfilename);
03526        }
03527        else if (maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, 1, 0))
03528        {
03529               cgi_put("error", "quota");
03530        }
03531        else
03532        {
03533               static char *filenamebuf=0;
03534 
03535               if (filenamebuf)
03536                      free(filenamebuf);
03537 
03538               filenamebuf=draftfilename;
03539               cgi_put("draftmessage", filenamebuf);
03540               return (0);
03541        }
03542        free(draftfilename);
03543        return (-1);
03544 }
03545 
03546 struct getedit_info {
03547        int fd;
03548        int flag;
03549 
03550        int in_headers;
03551        int sol;
03552        int skiph;
03553 
03554 } ;
03555 
03556 static int get_date(struct PCP_retr *r, time_t start, time_t end, void *vp)
03557 {
03558        char buf[NUMBUFSIZE];
03559        struct getedit_info *ge=(struct getedit_info *)vp;
03560 
03561        maildir_writemsgstr(ge->fd, "X-Event-Time: ");
03562        maildir_writemsgstr(ge->fd, libmail_str_time_t(start, buf));
03563        maildir_writemsgstr(ge->fd, " ");
03564        maildir_writemsgstr(ge->fd, libmail_str_time_t(end, buf));
03565        maildir_writemsgstr(ge->fd, "\n");
03566 
03567        return (0);
03568 }
03569 
03570 static int get_participants(struct PCP_retr *r, const char *address,
03571                          const char *dummy, void *vp)
03572 {
03573        struct getedit_info *ge=(struct getedit_info *)vp;
03574 
03575        maildir_writemsgstr(ge->fd, "X-Event-Participant: ");
03576        maildir_writemsgstr(ge->fd, address);
03577        maildir_writemsgstr(ge->fd, "\n");
03578 
03579        return (0);
03580 }
03581 
03582 static int get_msgtext(struct PCP_retr *r, const char *ptr, int n, void *vp)
03583 {
03584        struct getedit_info *ge=(struct getedit_info *)vp;
03585 
03586        /* We want to drop all X headers when we read in this event */
03587        /* Also, drop CRs */
03588 
03589        ge->flag=1;
03590 
03591        while (n)
03592        {
03593               int i;
03594 
03595               if (!ge->in_headers) /* Write out msg body */
03596               {
03597                      while (n)
03598                      {
03599                             if (*ptr == '\r')
03600                             {
03601                                    ++ptr;
03602                                    --n;
03603                                    continue;
03604                             }
03605 
03606                             for (i=0; i<n; i++)
03607                                    if (ptr[i] == '\r')
03608                                           break;
03609 
03610                             maildir_writemsg(ge->fd, ptr, i);
03611                             ptr += i;
03612                             n -= i;
03613                      }
03614                      break;
03615               }
03616 
03617               if (*ptr == '\r')
03618               {
03619                      ++ptr;
03620                      --n;
03621                      continue;
03622               }
03623 
03624               if (*ptr == '\n')
03625               {
03626                      if (!ge->skiph)
03627                             maildir_writemsgstr(ge->fd, "\n");
03628 
03629                      ge->skiph=0;
03630                      if (ge->sol)
03631                             ge->in_headers=0;    /* End of headers */
03632                      ge->sol=1;
03633                      ++ptr;
03634                      --n;
03635                      continue;
03636               }
03637 
03638               if (ge->sol && (*ptr == 'x' || *ptr == 'X'))
03639                      ge->skiph=1;
03640 
03641               for (i=0; i<n; i++)
03642                      if (ptr[i] == '\r' || ptr[i] == '\n')
03643                             break;
03644 
03645               if (!ge->skiph)      /* Skip X- header */
03646                      maildir_writemsg(ge->fd, ptr, i);
03647               ptr += i;
03648               n -= i;
03649        }
03650        return (0);
03651 }
03652 
03653 static int doeventedit(struct PCP *pcp, int fd)
03654 {
03655        const char *p=cgi("eventid");
03656        struct PCP_retr r;
03657        struct getedit_info ge;
03658 
03659        const char *eventid[2];
03660 
03661        if (!p || !*p)
03662               return (-1);
03663 
03664        maildir_writemsgstr(fd, "X-Event: 1\nX-Old-EventId: ");
03665        maildir_writemsgstr(fd, p);
03666        maildir_writemsgstr(fd, "\n");
03667 
03668        memset(&r, 0, sizeof(r));
03669        eventid[0]=p;
03670        eventid[1]=NULL;
03671 
03672        r.event_id_list=eventid;
03673 
03674        ge.fd=fd;
03675        ge.flag=0;
03676        r.callback_arg=&ge;
03677 
03678        r.callback_retr_date=get_date;
03679        r.callback_retr_participants=get_participants;
03680 
03681        if (pcp_retr(pcp, &r))
03682        {
03683               saveerror(pcp, &r.errcode);
03684               return (-1);
03685        }
03686 
03687        memset(&r, 0, sizeof(r));
03688        eventid[0]=p;
03689        eventid[1]=NULL;
03690 
03691        r.event_id_list=eventid;
03692 
03693        ge.fd=fd;
03694        ge.flag=0;
03695        r.callback_arg=&ge;
03696 
03697        ge.in_headers=1;
03698        ge.sol=1;
03699        ge.skiph=0;
03700 
03701        r.callback_rfc822_func=get_msgtext;
03702        if (pcp_retr(pcp, &r))
03703        {
03704               saveerror(pcp, &r.errcode);
03705               return (-1);
03706        }
03707 
03708        if (!ge.flag)
03709        {
03710               cgi_put("error", "notfound");
03711               return (-1);
03712        }
03713 
03714        return (0);
03715 }
03716 
03717 /* ------ Weekly stuff ------- */
03718 
03719 static void prevday(time_t *tm)
03720 {
03721        struct tm *tmptr;
03722        time_t t= *tm - 12 * 60 * 60;
03723 
03724        if ((tmptr=localtime(&t)) == NULL)
03725        {
03726               enomem();
03727               return;
03728        }
03729 
03730        if (pcp_parse_ymd(tmptr->tm_year + 1900, tmptr->tm_mon + 1,
03731                        tmptr->tm_mday, tm, &t))
03732        {
03733               enomem();
03734        }
03735 }
03736 
03737 static void nextday(time_t *tm)
03738 {
03739        struct tm *tmptr;
03740        time_t t= *tm + 36 * 60 * 60;
03741 
03742        if ((tmptr=localtime(&t)) == NULL)
03743        {
03744               enomem();
03745               return;
03746        }
03747 
03748        if (pcp_parse_ymd(tmptr->tm_year + 1900, tmptr->tm_mon + 1,
03749                        tmptr->tm_mday, tm, &t))
03750        {
03751               enomem();
03752        }
03753 }
03754 
03755 static time_t get_start_of_week()
03756 {
03757        unsigned y, m, d;
03758        time_t start;
03759        time_t end;
03760        struct tm *tmptr;
03761        int i;
03762 
03763        if (sscanf(cgi("weekof"), "%4u%2u%2u", &y, &m, &d) != 3
03764            || pcp_parse_ymd(y, m, d, &start, &end))
03765        {
03766               time(&start);
03767               if ((tmptr=localtime(&start)) == NULL)
03768               {
03769                      enomem();
03770                      return (0);
03771               }
03772               y=tmptr->tm_year + 1900;
03773               m=tmptr->tm_mon + 1;
03774               d=tmptr->tm_mday;
03775 
03776               if (pcp_parse_ymd(y, m, d, &start, &end))
03777               {
03778                      enomem();
03779                      return (0);
03780               }
03781        }
03782 
03783        for (i=0; i<7; i++)
03784        {
03785               tmptr=localtime(&start);
03786               if (!tmptr)
03787                      enomem();
03788 
03789               if (tmptr->tm_wday == pref_startofweek)
03790                      break;
03791 
03792               prevday(&start);
03793        }
03794 
03795        return (start);
03796 }
03797 
03798 void sqpcp_show_cal_week()
03799 {
03800        time_t start=get_start_of_week();
03801        struct tm *tmptr;
03802        char buf[512];
03803 
03804        if ((tmptr=localtime(&start)) == NULL)
03805               return;
03806 
03807        if (strftime(buf, sizeof(buf), getarg("DATEFORMAT"), tmptr) == 0)
03808               return;
03809 
03810        print_safe(buf);
03811 }
03812 
03813 void sqpcp_show_cal_nextweek()
03814 {
03815        time_t start=get_start_of_week();
03816        int i;
03817        struct tm *tmptr;
03818 
03819        for (i=0; i<7; i++)
03820               nextday(&start);
03821 
03822        if ((tmptr=localtime(&start)) == NULL)
03823               return;
03824 
03825        output_scriptptrget();
03826        printf("&amp;form=eventweekly&amp;weekof=%04d%02d%02d",
03827               tmptr->tm_year + 1900, tmptr->tm_mon+1, tmptr->tm_mday);
03828 
03829 }
03830 
03831 void sqpcp_show_cal_prevweek()
03832 {
03833        time_t start=get_start_of_week();
03834        int i;
03835        struct tm *tmptr;
03836 
03837        for (i=0; i<7; i++)
03838               prevday(&start);
03839 
03840        if ((tmptr=localtime(&start)) == NULL)
03841               return;
03842 
03843        output_scriptptrget();
03844        printf("&amp;form=eventweekly&amp;weekof=%04d%02d%02d",
03845               tmptr->tm_year + 1900, tmptr->tm_mon+1, tmptr->tm_mday);
03846 
03847 }
03848 
03849 void sqpcp_displayweek()
03850 {
03851        int i;
03852        time_t start=get_start_of_week(), save_start;
03853        time_t end;
03854        struct PCP *pcp=sqpcp_calendar();
03855        struct cacherecord *recs;
03856        unsigned n_recs;
03857 
03858        if (!pcp)
03859               return;
03860 
03861        save_start=start;
03862 
03863        for (i=0; i<7; i++)
03864        {
03865               nextday(&start);
03866        }
03867 
03868        if (createcache(pcp, &recs, &n_recs, save_start, start))
03869        {
03870               show_pcp_errmsg(pcp_errmsg(pcp));
03871               return;
03872        }
03873 
03874        printf("<table align=\"center\" border=\"0\" class=\"weekly-border\""
03875               " cellpadding=\"0\" cellspacing=\"0\" width=\"100%%\">"
03876               "<tr><td>\n");
03877        printf("<table border=\"1\" class=\"weekly-bg\" cellspacing=\"0\" cellpadding=\"10\" width=\"100%%\">"
03878               "<tr valign=\"top\">");
03879 
03880        start=save_start;
03881        for (i=0; i<7; i++)
03882        {
03883               const char *p;
03884               struct tm *tmptr;
03885 
03886               printf("<td width=\"14%%\">");
03887               p=pcp_wdayname((i + pref_startofweek) % 7);
03888               printf("<div align=\"center\" class=\"weekly-day\">");
03889               printf("<a href=\"");
03890               output_scriptptrget();
03891               printf("&amp;form=eventdaily&amp;date=");
03892 
03893               tmptr=localtime(&start);
03894 
03895               if (tmptr)
03896               {
03897                      printf("%04d%02d%02d", tmptr->tm_year + 1900,
03898                             tmptr->tm_mon+1,
03899                             tmptr->tm_mday);
03900               }
03901               printf("\">");
03902               print_safe(p);
03903               printf("</a><hr width=\"70%%\" />");
03904               printf("</div>\n");
03905 
03906               end=start;
03907               nextday(&end);
03908 
03909 
03910               do_daily_view(recs, n_recs, VIEW_WEEKLY, &start, &end);
03911 
03912               start=end;
03913               printf("</td>");
03914        }
03915        destroycache(recs, n_recs);
03916        printf("</tr></table>\n");
03917        printf("</td></tr></table>\n");
03918 }
03919 
03920 /* ---------------- Monthly view ---------------- */
03921 
03922 static time_t get_start_of_month()
03923 {
03924        unsigned y, m;
03925        time_t start;
03926        time_t end;
03927        struct tm *tmptr;
03928 
03929        if (sscanf(cgi("monthof"), "%4u%2u", &y, &m) != 2
03930            || pcp_parse_ymd(y, m, 1, &start, &end))
03931        {
03932               time(&start);
03933               if ((tmptr=localtime(&start)) == NULL)
03934               {
03935                      enomem();
03936                      return (0);
03937               }
03938               y=tmptr->tm_year + 1900;
03939               m=tmptr->tm_mon + 1;
03940 
03941               if (pcp_parse_ymd(y, m, 1, &start, &end))
03942               {
03943                      enomem();
03944                      return (0);
03945               }
03946        }
03947 
03948        return (start);
03949 }
03950 
03951 void sqpcp_show_cal_month()
03952 {
03953        time_t start=get_start_of_month();
03954        struct tm *tmptr;
03955        char buf[512];
03956 
03957        if ((tmptr=localtime(&start)) == NULL)
03958               return;
03959 
03960        if (strftime(buf, sizeof(buf), getarg("DATEFORMAT"), tmptr) == 0)
03961               return;
03962 
03963        print_safe(buf);
03964 
03965 }
03966 
03967 void sqpcp_show_cal_nextmonth()
03968 {
03969        time_t start=get_start_of_month();
03970        struct tm *tmptr;
03971        int m, y;
03972 
03973        if ((tmptr=localtime(&start)) == NULL)
03974               return;
03975 
03976        y=tmptr->tm_year + 1900;
03977        m=tmptr->tm_mon + 1;
03978 
03979        ++m;
03980        if (m > 12)
03981        {
03982               m=1;
03983               ++y;
03984        }
03985 
03986        output_scriptptrget();
03987        printf("&amp;form=eventmonthly&amp;monthof=%04d%02d01", y, m);
03988 }
03989 
03990 void sqpcp_show_cal_prevmonth()
03991 {
03992        time_t start=get_start_of_month();
03993        struct tm *tmptr;
03994        int m, y;
03995 
03996        if ((tmptr=localtime(&start)) == NULL)
03997               return;
03998 
03999        y=tmptr->tm_year + 1900;
04000        m=tmptr->tm_mon + 1;
04001 
04002        --m;
04003        if (m <= 0)
04004        {
04005               m=12;
04006               --y;
04007        }
04008 
04009        output_scriptptrget();
04010        printf("&amp;form=eventmonthly&amp;monthof=%04d%02d01", y, m);
04011 }
04012 
04013 void sqpcp_displaymonth()
04014 {
04015        int i, y, m;
04016        time_t start=get_start_of_month(), save_start;
04017        time_t end;
04018        struct PCP *pcp=sqpcp_calendar();
04019        struct cacherecord *recs;
04020        unsigned n_recs;
04021        struct tm *tmptr;
04022 
04023        if (!pcp)
04024               return;
04025 
04026        if ((tmptr=localtime(&start)) == NULL)
04027               return;
04028 
04029        y=tmptr->tm_year + 1900;
04030        m=tmptr->tm_mon + 1;
04031 
04032        if (++m > 12)
04033        {
04034               m=1;
04035               ++y;
04036        }
04037 
04038        if (pcp_parse_ymd(y, m, 1, &end, &save_start))
04039               return;
04040 
04041        if (createcache(pcp, &recs, &n_recs, start, end))
04042        {
04043               show_pcp_errmsg(pcp_errmsg(pcp));
04044               return;
04045        }
04046 
04047        printf("<table align=\"center\" border=\"0\" class=\"monthly-border\""
04048               " cellpadding=\"0\" cellspacing=\"0\" width=\"100%%\">"
04049               "<tr><td>\n");
04050        printf("<table border=\"1\" class=\"monthly-bg\" cellspacing=\"0\" cellpadding=\"10\" width=\"100%%\">"
04051               "<tr valign=\"top\">");
04052 
04053        for (i=0; i<7; i++)
04054        {
04055               printf("<td width=\"14%%\" align=\"center\" class=\"monthly-day\">");
04056               print_safe(pcp_wdayname((i + pref_startofweek) % 7));
04057               printf("</td>");
04058        }
04059        printf("</tr>\n");
04060 
04061        while (start < end)
04062        {
04063               printf("<tr valign=\"top\">\n");
04064 
04065               for (i=0; i<7; i++)
04066               {
04067                      struct tm *tmptr;
04068                      time_t next_day;
04069 
04070                      tmptr=localtime(&start);
04071 
04072                      if (tmptr->tm_wday != (i + pref_startofweek) % 7
04073                          || start >= end)
04074                      {
04075                             printf("<td width=\"14%%\" class=\"monthly-bg-othermonth\">&nbsp;</td>");
04076                             continue;
04077                      }
04078 
04079                      printf("<td width=\"14%%\">");
04080 
04081 
04082                      printf("<a href=\"");
04083                      output_scriptptrget();
04084                      printf("&amp;form=eventdaily&amp;date=");
04085 
04086                      if (tmptr)
04087                      {
04088                             printf("%04d%02d%02d", tmptr->tm_year + 1900,
04089                                    tmptr->tm_mon+1,
04090                                    tmptr->tm_mday);
04091                      }
04092                      printf("\" class=\"monthly-day\">");
04093 
04094                      printf("%2d", tmptr->tm_mday);
04095                      printf("</a><div align=\"center\"><hr width=\"70%%\" /></div>\n");
04096 
04097                      next_day=start;
04098                      nextday(&next_day);
04099 
04100                      do_daily_view(recs, n_recs, VIEW_MONTHLY, &start,
04101                                   &next_day);
04102 
04103                      start=next_day;
04104                      printf("</td>\n");
04105               }
04106               printf("</tr>\n");
04107        }
04108        destroycache(recs, n_recs);
04109        printf("</table>\n");
04110        printf("</td></tr></table>\n");
04111 }
04112 
04113 /* -------------------------------------------------------------------- */
04114 /* Access control lists */
04115 
04116 static void addacl(const char *);
04117 
04118 struct acl_list {
04119        struct acl_list *next;
04120        char *addr;
04121        char *name;
04122        int flags;
04123 } ;
04124 
04125 static int listacl(const char *a, int f, void *vp)
04126 {
04127        struct acl_list **p=(struct acl_list **)vp, *q;
04128 
04129        if ((q=malloc(sizeof(struct acl_list))) == NULL)
04130               return (-1);
04131        memset(q, 0, sizeof(*q));
04132        if ((q->addr=strdup(a)) == NULL)
04133        {
04134               free(q);
04135               return (-1);
04136        }
04137 
04138        q->flags=f;
04139 
04140        while (*p)
04141        {
04142               if (strcasecmp( (*p)->addr, a) > 0)
04143                      break;
04144               p= &(*p)->next;
04145        }
04146 
04147        q->next= *p;
04148        *p=q;
04149        return (0);
04150 }
04151 
04152 static int save_listacl_names(const char *addr, const char *name,
04153                            void *vp)
04154 {
04155        struct acl_list *p=(struct acl_list *)vp;
04156 
04157        for ( ; name && p; p=p->next)
04158               if (strcasecmp(p->addr, addr) == 0 && p->name == 0)
04159                      p->name=strdup(name);
04160        return (0);
04161 }
04162 
04163 void sqpcp_eventacl()
04164 {
04165        const char *p;
04166        struct acl_list *acl_list=NULL;
04167        struct PCP *pcp;
04168        struct acl_list *pp;
04169 
04170        if (!sqpcp_has_groupware())
04171               return;
04172 
04173        p=cgi("addemail");
04174 
04175        while (*p && isspace((int)(unsigned char)*p))
04176               ++p;
04177 
04178        if (!*p)
04179               p=cgi("addressbookname");
04180 
04181        if (*p)
04182               addacl(p);
04183 
04184        pcp=sqpcp_calendar();
04185 
04186        if (!pcp)
04187               return;
04188 
04189        if (*(p=cgi("remove")))
04190        {
04191               if (pcp_acl(pcp, p, 0))
04192               {
04193                      saveerror(pcp, NULL);
04194                      showerror();
04195               }
04196        }
04197 
04198        if (pcp_list_acl(pcp, listacl, &acl_list))
04199        {
04200               saveerror(pcp, NULL);
04201               showerror();
04202        }
04203        else if (ab_get_nameaddr(save_listacl_names, acl_list))
04204        {
04205               int dummy=PCP_ERR_SYSERR;
04206 
04207               saveerror(NULL, &dummy);
04208               showerror();
04209        }
04210        else if (acl_list)
04211        {
04212               printf("<table align=\"center\">\n");
04213 
04214               for (pp=acl_list; pp; pp=pp->next)
04215               {
04216                      printf("<tr><td align=\"right\"><span class=\"tt\">");
04217                      if (pp->addr)
04218                             ab_nameaddr_show(pp->name, pp->addr);
04219 
04220                      printf("</span></td><td>-");
04221                      if (pp->flags & PCP_ACL_MODIFY)
04222                             printf("&nbsp;%s", getarg("MODIFY"));
04223                      if (pp->flags & PCP_ACL_CONFLICT)
04224                             printf("&nbsp;%s", getarg("CONFLICT"));
04225                      printf("</td><td><a href=\"");
04226                      output_scriptptrget();
04227                      printf("&amp;form=eventacl&amp;remove=");
04228                      output_urlencoded(pp->addr);
04229                      printf("\">%s</a></td></tr>\n", getarg("REMOVE"));
04230               }
04231               printf("</table>\n");
04232        }
04233 
04234        while ((pp=acl_list) != NULL)
04235        {
04236               acl_list=pp->next;
04237               if (pp->addr)
04238                      free(pp->addr);
04239               if (pp->name)
04240                      free(pp->name);
04241               free(pp);
04242        }
04243 }
04244 
04245 static void addacl(const char *p)
04246 {
04247        int flags=0;
04248        struct PCP *pcp;
04249 
04250        if (strchr(p, '@') == NULL)
04251        {
04252               const char *mhn=myhostname();
04253               char *q=malloc(strlen(p)+strlen(mhn)+2);
04254 
04255               if (!q)
04256                      enomem();
04257 
04258               strcat(strcat(strcpy(q, p), "@"), mhn);
04259               addacl(q);
04260               free(q);
04261               return;
04262        }
04263 
04264        if (*cgi("aclMODIFY"))
04265               flags |= PCP_ACL_MODIFY;
04266 
04267        if (*cgi("aclCONFLICT"))
04268               flags |= PCP_ACL_CONFLICT;
04269 
04270        if (!flags)
04271               return;       /* Noop */
04272 
04273        pcp=sqpcp_calendar();
04274 
04275        if (!pcp)
04276        {
04277               int xerror=PCP_ERR_SYSERR;
04278 
04279               saveerror(NULL, &xerror);
04280               showerror();
04281               return;
04282        }
04283 
04284        if (!pcp_has_acl(pcp))
04285        {
04286               printf("%s\n", getarg("NOACL"));
04287               return;
04288        }
04289 
04290        if (pcp_acl(pcp, p, flags))
04291        {
04292               saveerror(pcp, NULL);
04293               showerror();
04294               return;
04295        }
04296 }