1 /*
2 ** Copyright 2001-2010 Double Precision, Inc.  See COPYING for
3 ** distribution information.
4 */
5 
6 
7 /*
8 */
9 #include	"sqwebmail.h"
10 #include	"pcp.h"
11 #include	"pref.h"
12 #include	"htmllibdir.h"
13 #include	"sqconfig.h"
14 #include	"auth.h"
15 #include	"addressbook.h"
16 #include	"pcp/pcp.h"
17 #include	"cgi/cgi.h"
18 #include	"rfc822/rfc822.h"
19 #include	"rfc822/rfc822hdr.h"
20 #include	"rfc822/rfc2047.h"
21 #include	"maildir/maildircreate.h"
22 #include	"maildir/maildirmisc.h"
23 #include	"maildir/maildirquota.h"
24 #include	"maildir/maildirgetquota.h"
25 #include	"numlib/numlib.h"
26 #include	"maildir.h"
27 #include	"newmsg.h"
28 #include	"pref.h"
29 #include	"courierauth.h"
30 #include	<stdio.h>
31 #include	<string.h>
32 #include	<stdlib.h>
33 #include	<signal.h>
34 #include	<ctype.h>
35 #include	<unistd.h>
36 #include	<errno.h>
37 #include	<sys/types.h>
38 #include	<sys/stat.h>
39 #if HAVE_SYS_WAIT_H
40 #include	<sys/wait.h>
41 #endif
42 #if HAVE_FCNTL_H
43 #include	<fcntl.h>
44 #endif
45 
46 #ifndef WEXITSTATUS
47 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
48 #endif
49 #ifndef WIFEXITED
50 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
51 #endif
52 
53 #define		CACHE	"calendar.cache"
54 #define		TOKEN	"calendar.authtoken"
55 
56 #define		CHANGEDFILE "calendar/changed"	/* Hack */
57 
58 #include	"strftime.h"
59 
60 extern FILE *open_langform(const char *lang, const char *formname,
61 			   int print_header);
62 
63 extern const char *myhostname();
64 extern void output_attrencoded_oknl_fp(const char *, FILE *);
65 extern void output_scriptptrget();
66 extern void output_attrencoded(const char *);
67 extern void print_safe(const char *);
68 extern const char *sqwebmail_content_charset;
69 extern const char *sqwebmail_content_language;
70 extern void output_form(const char *);
71 extern void newmsg_preview(const char *);
72 extern void output_urlencoded(const char *);
73 extern void attachments_head(const char *, const char *, const char *);
74 extern char *newmsg_createsentmsg(const char *, int *);
75 extern const char *sqwebmail_mailboxid;
76 extern char *scriptptrget();
77 extern void attach_delete(const char *);
78 extern int attach_upload(const char *,
79 			 const char *,
80 			 const char *);
81 
82 extern void newmsg_showfp(FILE *, int *);
83 
84 static struct PCP *calendar=NULL;
85 static void refreshcache(struct PCP *);
86 extern size_t get_timeoutsoft();
87 
88 
89 /*
90 ** CGI process startup
91 */
92 
sqpcp_init()93 void sqpcp_init()
94 {
95 	calendar=NULL;
96 }
97 
98 /*
99 ** CGI process shutdown
100 */
101 
sqpcp_close()102 void sqpcp_close()
103 {
104 	if (calendar)
105 	{
106 		pcp_close(calendar);
107 		calendar=NULL;
108 	}
109 }
110 
111 static int checked_calendar_mode=0;
112 static char calendar_mode[24];
113 
sqpcp_mode()114 static const char *sqpcp_mode()
115 {
116 	if (!checked_calendar_mode)
117 	{
118 		FILE *f;
119 		char *p;
120 
121 		calendar_mode[0]=0;
122 
123 		f=fopen(CALENDARMODE, "r");
124 
125 		if (f)
126 		{
127 			if (fgets(calendar_mode, sizeof(calendar_mode),
128 				  f) == NULL)
129 			{
130 				calendar_mode[0]=0;
131 			}
132 			fclose(f);
133 		}
134 
135 		if ((p=strchr(calendar_mode, '\n')) != 0)
136 			*p=0;
137 		checked_calendar_mode=1;
138 	}
139 
140 	return (calendar_mode[0] ? calendar_mode:NULL);
141 }
142 
143 /*
144 ** Log in to calendar.
145 */
146 
147 static void do_pcplogin(const char *userid, const char *password, int showerr);
148 
sqpcp_login(const char * userid,const char * password)149 void sqpcp_login(const char *userid, const char *password)
150 {
151 	do_pcplogin(userid, password, 0);
152 }
153 
do_pcplogin(const char * userid,const char * password,int showerr)154 static void do_pcplogin(const char *userid, const char *password, int showerr)
155 {
156 	struct PCP *pcp;
157 
158 	unlink(TOKEN);
159 	unlink(CACHE);	/* Rebuild it later*/
160 
161 	if (!sqpcp_mode())
162 		return;
163 
164 	mkdir("calendar", 0700);
165 
166 	if (sqpcp_has_groupware())	/* Groupware mode, login to server */
167 	{
168 		char *errflag=0;
169 
170 		pcp=pcp_open_server(userid, password, &errflag);
171 
172 		if (!pcp && errflag && showerr)
173 		{
174 			printf("%s<div class=\"indent\"><pre class=\"small-error\">",
175 			       getarg("CALENDARLOGINERR"));
176 			output_attrencoded_oknl_fp(errflag, stdout);
177 			printf("</pre></div>\n");
178 		}
179 		if (errflag)
180 			free(errflag);
181 	}
182 	else
183 	{
184 		pcp=sqpcp_calendar();
185 	}
186 
187 	if (pcp)
188 	{
189 		const char *p=pcp_authtoken(pcp);
190 
191 		if (p)
192 		{
193 			FILE *f;
194 			int u=umask(077);
195 
196 			f=fopen(TOKEN, "w");
197 			umask(u);
198 			if (f)
199 			{
200 				fprintf(f, "%s\n", p);
201 				fclose(f);
202 			}
203 		}
204 		pcp_cleanup(pcp);
205 		refreshcache(pcp);
206 	}
207 }
208 
209 /*
210 ** Format of the CACHE file:
211 **
212 **  start<TAB>end<TAB>eventid<TAB>flags<TAB>subject
213 */
214 
215 struct cacherecord {
216 	time_t start, end;
217 	char *eventid;
218 	char *flags;
219 	char *subject;
220 } ;
221 
sqpcp_has_calendar()222 int sqpcp_has_calendar()
223 {
224 	return (sqpcp_mode() ? 1:0);
225 }
226 
sqpcp_has_groupware()227 int sqpcp_has_groupware()
228 {
229 	const char *p=sqpcp_mode();
230 
231 	return (p && strcmp(p, "net") == 0);
232 }
233 
234 static int createcache(struct PCP *,
235 		       struct cacherecord **, unsigned *, time_t, time_t);
236 static void destroycache(struct cacherecord *, unsigned);
237 
238 /*
239 ** Are we logged in?  If so, refresh the calendar event cache that we
240 ** display on the main folders screen, if it is stale.
241 */
242 
243 static int need_refresh();
244 
sqpcp_loggedin()245 int sqpcp_loggedin()
246 {
247 	struct PCP *pcp;
248 
249 	if (!sqpcp_mode())
250 		return (0);
251 
252 	if (sqpcp_has_groupware())
253 	{
254 		struct stat stat_buf;
255 
256 		if (stat(TOKEN, &stat_buf))
257 			return (0);	/* Login session dropped */
258 	}
259 
260 	if (!need_refresh())
261 		return (1);
262 	pcp=sqpcp_calendar();
263 	if (pcp)
264 		refreshcache(pcp);
265 	return (1);
266 }
267 
268 /* Check if it's time to rebuild CACHE file */
269 
parsetimet(const char * buf,time_t * tp)270 static const char *parsetimet(const char *buf, time_t *tp)
271 {
272 	*tp=libmail_strtotime_t(&buf);
273 
274 	if (*buf == '\t')
275 		++buf;
276 	return buf;
277 }
278 
need_refresh()279 static int need_refresh()
280 {
281 	FILE *fp;
282 	struct stat stat_buf;
283 
284 	/* Check whether it's time to rebuild the cache */
285 
286 	fp=fopen(CACHE, "r");
287 
288 	if (stat(CHANGEDFILE, &stat_buf) == 0)
289 	{
290 		if (fp)
291 			fclose(fp);
292 		return (1);
293 	}
294 
295 	if (fp)
296 	{
297 		struct stat stat_buf;
298 
299 		char buffer[BUFSIZ];
300 		const char *p;
301 
302 		time_t a, b;
303 
304 		int ch=getc(fp);
305 
306 		if (ch == EOF)
307 		{
308 			fclose(fp);
309 			return (0); /* No events scheduled */
310 		}
311 
312 		ungetc(ch, fp);
313 		if (fgets(buffer, sizeof(buffer), fp) &&
314 		    (p=parsetimet(buffer, &a)) &&
315 		    parsetimet(p, &b))
316 		{
317 			time_t now;
318 
319 			time(&now);
320 
321 			if (now < b)	/* Event expired */
322 			{
323 				if (fstat(fileno(fp), &stat_buf) == 0)
324 				{
325 					/*
326 					** Check in every TIMEOUTSOFT/2 in
327 					** any case.
328 					*/
329 
330 					if (stat_buf.st_mtime >
331 					    now - get_timeoutsoft()/2)
332 					{
333 						fclose(fp);	/* Not yet */
334 						return (0);
335 					}
336 				}
337 			}
338 		}
339 		fclose(fp);
340 		unlink(CACHE);
341 		return (1);
342 	}
343 	return (0);
344 }
345 
refreshcache(struct PCP * pcp)346 static void refreshcache(struct PCP *pcp)
347 {
348 	struct cacherecord *recs;
349 	unsigned n_recs;
350 	unsigned i;
351 	char *new_name;
352 	int new_fd;
353 	char *p;
354 	time_t now;
355 	FILE *new_fp;
356 
357 	unlink(CHANGEDFILE);
358 	time(&now);
359 	if (createcache(pcp, &recs, &n_recs, now, now + 5 * 24 * 60 * 60))
360 		return;
361 
362 	new_fd=maildir_createmsg(INBOX, "cache", &new_name);
363 	if (new_fd < 0 || (new_fp=fdopen(new_fd, "w")) == 0)
364 	{
365 		if (new_fd >= 0)        close(new_fd);
366 		destroycache(recs, n_recs);
367 		return;
368 	}
369 
370         p=malloc(sizeof("tmp/")+strlen(new_name));
371         if (!p)
372         {
373 		fclose(new_fp);
374                 free(new_name);
375 		destroycache(recs, n_recs);
376                 return;
377         }
378         strcat(strcpy(p, "tmp/"), new_name);
379         free(new_name);
380         new_name=p;
381 
382 	/* Save a max of 5 events, for the main page listing */
383 
384 	for (i=0; i<n_recs && i < 5; i++)
385 	{
386 		char buf1[NUMBUFSIZE], buf2[NUMBUFSIZE];
387 
388 		fprintf(new_fp, "%s\t%s\t%s\t%s\t%s\n",
389 			libmail_str_time_t(recs[i].start, buf1),
390 			libmail_str_time_t(recs[i].end, buf2),
391 			recs[i].eventid,
392 			recs[i].flags,
393 			recs[i].subject);
394 	}
395 
396 	if (fflush(new_fp) || ferror(new_fp))
397 	{
398 		fclose(new_fp);
399 		unlink(new_name);
400                 free(new_name);
401 		destroycache(recs, n_recs);
402                 return;
403         }
404 	fclose(new_fp);
405 	rename(new_name, CACHE);
406 	free(new_name);
407 	destroycache(recs, n_recs);
408 	return;
409 }
410 
411 struct cacherecord_list {
412 	struct cacherecord_list *next;
413 	struct cacherecord rec;
414 } ;
415 
cmp_reclist(const void * a,const void * b)416 static int cmp_reclist(const void *a, const void *b)
417 {
418 	struct cacherecord_list *aa=*(struct cacherecord_list **)a;
419 	struct cacherecord_list *bb=*(struct cacherecord_list **)b;
420 
421 	return ( aa->rec.end < bb->rec.end ? -1:
422 		 aa->rec.end > bb->rec.end ? 1:
423 		 aa->rec.start < bb->rec.start ? -1:
424 		 aa->rec.start > bb->rec.start ? 1:
425 		 strcmp(aa->rec.eventid, bb->rec.eventid));
426 }
427 
428 static int callback_createcache(struct PCP_list_all *, void *);
429 static int callback_retr_status(struct PCP_retr *, int, void *);
430 static int callback_retr_headers(struct PCP_retr *, const char *,
431 				 const char *, void *);
432 
433 static void destroycache_rec(struct cacherecord *);
434 
435 struct retr_xinfo {
436 	struct cacherecord *recs;
437 	unsigned n_recs;
438 } ;
439 
createcache(struct PCP * pcp,struct cacherecord ** recs,unsigned * n_recs,time_t start,time_t end)440 static int createcache(struct PCP *pcp,
441 		       struct cacherecord **recs, unsigned *n_recs,
442 		       time_t start, time_t end)
443 {
444 	struct cacherecord_list *list=NULL, *p, **a;
445 	struct PCP_list_all la;
446 	struct PCP_retr r;
447 	struct retr_xinfo xr;
448 
449 	unsigned i,n;
450 	const char **event_ids;
451 
452 	*recs=0;
453 	*n_recs=0;
454 
455 	memset(&la, 0, sizeof(la));
456 	la.list_from=start;
457 	la.list_to=end;
458 	la.callback_func=callback_createcache;
459 	la.callback_arg= &list;
460 
461 	if (pcp_list_all(pcp, &la))
462 	{
463 		while ((p=list) != NULL)
464 		{
465 			list=p->next;
466 			destroycache_rec(&p->rec);
467 			free(p);
468 		}
469 		return (0);
470 	}
471 
472 	/* Sort the returned event list, in chronological order. */
473 
474 
475 	/* First, create an array out of the list */
476 
477 	for (n=0, p=list; p; p=p->next)
478 		++n;
479 
480 	if (!n)
481 		return (0);	/* Nothing */
482 
483 	a=malloc(sizeof(struct cacherecord_list *)*n);
484 	if (!a)
485 	{
486 		fprintf(stderr, "NOTICE: malloc failed\n");
487 
488 		while ((p=list) != NULL)
489 		{
490 			list=p->next;
491 			destroycache_rec(&p->rec);
492 			free(p);
493 		}
494 		return (-1);
495 	}
496 	for (n=0, p=list; p; p=p->next)
497 		a[n++]=p;
498 
499 	/* Sort it, copy the sorted array to the return ptr */
500 
501 	qsort(a, n, sizeof(*a), cmp_reclist);
502 
503 	if ((*recs=malloc(sizeof(struct cacherecord)*n)) == NULL)
504 	{
505 		fprintf(stderr, "NOTICE: malloc failed\n");
506 
507 		while ((p=list) != NULL)
508 		{
509 			list=p->next;
510 			destroycache_rec(&p->rec);
511 			free(p);
512 		}
513 		free(a);
514 		return (-1);
515 	}
516 
517 	for (i=0; i<n; i++)
518 		(*recs)[i]= a[i]->rec;
519 	*n_recs=n;
520 	free(a);
521 	while ((p=list) != NULL)
522 	{
523 		list=p->next;
524 		free(p);
525 	}
526 
527 	/* Get the subject of all the events */
528 
529 	event_ids=malloc(sizeof(const char *)*(n+1));
530 
531 	if (!event_ids)
532 	{
533 		fprintf(stderr, "NOTICE: malloc failed\n");
534 
535 		destroycache(*recs, *n_recs);
536 		return (-1);
537 	}
538 
539 	for (i=0; i< *n_recs; i++)
540 		event_ids[i]= (*recs)[i].eventid;
541 	event_ids[i]=NULL;
542 
543 	memset(&r, 0, sizeof(r));
544 	r.event_id_list=event_ids;
545 	r.callback_arg=&xr;
546 	xr.recs= *recs;
547 	xr.n_recs= *n_recs;
548 
549 	r.callback_retr_status=callback_retr_status;
550 	r.callback_headers_func=callback_retr_headers;
551 
552 	if (pcp_retr(pcp, &r))
553 	{
554 		fprintf(stderr, "NOTICE: pcp_retr: error: %s\n", pcp_errmsg(pcp));
555 		free(event_ids);
556 		destroycache(*recs, *n_recs);
557 		return (-1);
558 	}
559 	free(event_ids);
560 	return (0);
561 }
562 
563 /* Callback from PCP LIST - save the event ID in the cacherecord_list */
564 
callback_createcache(struct PCP_list_all * a,void * vp)565 static int callback_createcache(struct PCP_list_all *a, void *vp)
566 {
567 	struct cacherecord_list **listp=(struct cacherecord_list **)vp, *p;
568 
569 	if ((p=malloc(sizeof(struct cacherecord_list))) == NULL)
570 		return (-1);
571 
572 	p->rec.start=a->event_from;
573 	p->rec.end=a->event_to;
574 
575 	if ((p->rec.eventid=strdup(a->event_id)) == NULL)
576 	{
577 		free(p);
578 		return (-1);
579 	}
580 
581 	/* Initialize the other fields, so all ptrs are live */
582 
583 	if ((p->rec.flags=strdup("")) == NULL)
584 	{
585 		free(p->rec.eventid);
586 		free(p);
587 		return (-1);
588 	}
589 
590 	if ((p->rec.subject=strdup("")) == NULL)
591 	{
592 		free(p->rec.flags);
593 		free(p->rec.eventid);
594 		free(p);
595 		return (-1);
596 	}
597 
598 	p->next= *listp;
599 	*listp=p;
600 	return (0);
601 }
602 
callback_retr_status(struct PCP_retr * r,int s,void * vp)603 static int callback_retr_status(struct PCP_retr *r, int s, void *vp)
604 {
605 	struct cacherecord *recs=( (struct retr_xinfo *)vp)->recs;
606 	unsigned n_recs=( (struct retr_xinfo *)vp)->n_recs;
607 	unsigned i;
608 
609 	char stat_buf[256];
610 	char *p;
611 
612 	stat_buf[0]=0;
613 
614 	if (s & LIST_CANCELLED)
615 	{
616 		strcat(stat_buf, " CANCELLED");
617 	}
618 
619 	if (s & LIST_BOOKED)
620 	{
621 		strcat(stat_buf, " BOOKED");
622 	}
623 
624 	p=stat_buf;
625 	if (*p)
626 		++p;
627 
628 	for (i=0; i<n_recs; i++)
629 	{
630 		if (strcmp(recs[i].eventid, r->event_id) == 0)
631 		{
632 			char *s=strdup(p);
633 
634 			if (!s)
635 				return (-1);
636 			free(recs[i].flags);
637 			recs[i].flags=s;
638 			break;
639 		}
640 	}
641 	return (0);
642 }
643 
644 /* RETR callback for headers - save the Subject: header */
645 
collapse_subject(char * s)646 static void collapse_subject(char *s)
647 {
648 	/* Collapse multiline subjects */
649 
650 	char *t, *u;
651 
652 	for (t=u=s; *t; )
653 	{
654 		if (*t != '\n')
655 		{
656 			*u++=*t++;
657 			continue;
658 		}
659 
660 		while (*t && isspace((int)(unsigned char)*t))
661 			++t;
662 		*u++=' ';
663 	}
664 	*u=0;
665 }
666 
callback_retr_headers(struct PCP_retr * r,const char * h,const char * v,void * vp)667 static int callback_retr_headers(struct PCP_retr *r, const char *h,
668 				 const char *v, void *vp)
669 {
670 	struct cacherecord *recs=( (struct retr_xinfo *)vp)->recs;
671 	unsigned n_recs=( (struct retr_xinfo *)vp)->n_recs;
672 	unsigned i;
673 
674 	if (strcasecmp(h, "Subject") || !v)
675 		return (0);
676 
677 	for (i=0; i<n_recs; i++)
678 	{
679 		if (strcmp(recs[i].eventid, r->event_id) == 0)
680 		{
681 			char *s;
682 
683 			s=strdup(v);
684 
685 			if (!s)
686 				return (-1);
687 
688 			collapse_subject(s);
689 			free(recs[i].subject);
690 			recs[i].subject=s;
691 		}
692 	}
693 
694 	return (0);
695 }
696 
destroycache(struct cacherecord * c,unsigned n)697 static void destroycache(struct cacherecord *c, unsigned n)
698 {
699 	unsigned i;
700 
701 	for (i=0; i<n; i++)
702 	{
703 		destroycache_rec(c+i);
704 	}
705 	if (c)
706 		free(c);
707 }
708 
destroycache_rec(struct cacherecord * c)709 static void destroycache_rec(struct cacherecord *c)
710 {
711 	free(c->eventid);
712 	free(c->flags);
713 	free(c->subject);
714 }
715 
parsecache_rec(char * p,struct cacherecord * cr)716 static void parsecache_rec(char *p, struct cacherecord *cr)
717 {
718 	unsigned long a;
719 
720 	memset(cr, 0, sizeof(*cr));
721 	cr->eventid="";
722 	cr->flags="";
723 	cr->subject="";
724 
725 	if (!p || sscanf(p, "%lu", &a) <= 0)
726 		return;
727 	p=strchr(p, '\t');
728 	cr->start= (time_t)a;
729 	if (!p || sscanf(p, "%lu", &a) <= 0)
730 		return;
731 	cr->end= (time_t)a;
732 	p=strchr(p+1, '\t');
733 	if (!p) return;
734 	++p;
735 
736 	cr->eventid=p;
737 	p=strchr(p, '\t');
738 	if (!p) return;
739 	*p++=0;
740 
741 	cr->flags=p;
742 	p=strchr(p, '\t');
743 	if (!p) return;
744 	*p++=0;
745 
746 	cr->subject=p;
747 }
748 
sqpcp_calendar()749 struct PCP *sqpcp_calendar()
750 {
751 	const char *p;
752 
753 	if (!sqpcp_mode())
754 	{
755 		errno=ENOENT;
756 		return (NULL);
757 	}
758 
759 	if (calendar)
760 		return (calendar);
761 
762 	p=getenv("AUTHADDR");
763 
764 	if (!p)
765 	{
766 		errno=ENOENT;
767 		return (NULL);
768 	}
769 
770 	if (sqpcp_has_groupware())
771 	{
772 		char token[256];
773 		char *pp;
774 
775 		FILE *f=fopen(TOKEN, "r");
776 
777 		if (!f)
778 			return (NULL);
779 
780 		if (fgets(token, sizeof(token), f) == NULL)
781 		{
782 			fclose(f);
783 			return (NULL);
784 		}
785 
786 		if ((pp=strchr(token, '\n')) != 0) *pp=0;
787 
788 		fclose(f);
789 		if (token[0] == 0)
790 		{
791 			unlink(TOKEN);
792 			return (NULL);
793 		}
794 
795 		calendar=pcp_reopen_server(p, token, NULL);
796 
797 		if (calendar)
798 		{
799 			p=pcp_authtoken(calendar);
800 
801 			if (p && strcmp(p, token))
802 			{
803 				int u=umask(077);
804 
805 				/* Save new authentication token */
806 
807 				f=fopen(TOKEN, "w");
808 				umask(u);
809 				if (f)
810 				{
811 					fprintf(f, "%s\n", token);
812 					fclose(f);
813 				}
814 			}
815 		}
816 		else
817 		{
818 			unlink(TOKEN);
819 		}
820 		return (calendar);
821 	}
822 
823 	return ((calendar=pcp_open_dir("calendar", p)));
824 }
825 
826 
827 /* ---------------------------------------------------------------- */
828 /* Display event information */
829 /* ---------------------------------------------------------------- */
830 
831 static struct PCP_event_time *event_time_list=0;
832 static unsigned n_event_time_list=0;
833 static FILE *openoldfp(const char *p, unsigned long *prev_size);
834 
835 struct my_participant {
836 	struct my_participant *next;
837 	char *name;
838 	char *address;
839 } ;
840 
841 static struct my_participant *my_participant_list=0;
842 
add_my_participant(const char * h)843 static void add_my_participant(const char *h)
844 {
845 	struct my_participant *m=
846 		malloc(sizeof(struct my_participant));
847 
848 	if (!m)
849 		enomem();
850 
851 	memset(m, 0, sizeof(*m));
852 	m->next=my_participant_list;
853 	my_participant_list=m;
854 
855 	if ((m->address=strdup(h)) == NULL)
856 		enomem();
857 }
858 
859 static char *from_buf=0, *subj_buf=0;
860 
sqpcp_eventstart()861 void sqpcp_eventstart()
862 {
863 	const char *p=cgi("draftmessage");
864 	FILE *oldfp;
865 	struct rfc822hdr h;
866 	struct PCP_event_time_list {
867 		struct PCP_event_time_list *next;
868 		struct PCP_event_time t;
869 	} *event_time_listp=NULL, **lastp= &event_time_listp;
870 	unsigned event_time_list_cnt=0;
871 
872 	sqpcp_eventend();
873 
874 	if (!p || !*p)
875 		return;
876 
877 	oldfp=openoldfp(p, NULL);
878 	if (!oldfp)
879 		return;
880 
881 	rfc822hdr_init(&h, 8192);
882 	while (rfc822hdr_read(&h, oldfp, NULL, 0) == 0)
883 	{
884 		if (strcasecmp(h.header, "X-Event-Time") == 0 && h.value)
885 		{
886 			unsigned long n1, n2;
887 
888 			if (sscanf(h.value, "%lu %lu", &n1, &n2) == 2)
889 			{
890 				struct PCP_event_time_list *t=
891 					malloc(sizeof(**lastp));
892 
893 				if (!t)
894 				{
895 					rfc822hdr_free(&h);
896 					sqpcp_eventend();
897 					enomem();
898 					return;
899 				}
900 				*lastp=t;
901 				t->next=NULL;
902 				t->t.start=(time_t)n1;
903 				t->t.end=(time_t)n2;
904 				++event_time_list_cnt;
905 				lastp=&t->next;
906 			}
907 		}
908 		else if (strcasecmp(h.header, "X-Event-Participant") == 0 && h.value)
909 		{
910 			add_my_participant(h.value);
911 		}
912 		else if (strcasecmp(h.header, "from") == 0 && h.value)
913 		{
914 			rfc822hdr_collapse(&h);
915 			if (from_buf)
916 				free(from_buf);
917 
918 			from_buf=NULL;
919 
920 			if ((from_buf=
921 			     rfc822_display_hdrvalue_tobuf(h.header,
922 							   h.value,
923 							   sqwebmail_content_charset,
924 							   NULL, NULL)) == NULL)
925 				from_buf=strdup(h.value);
926 
927 			if (from_buf)
928 				cgi_put("from", from_buf);
929 		}
930 		else if (strcasecmp(h.header, "subject") == 0 && h.value)
931 		{
932 			rfc822hdr_collapse(&h);
933 			if (subj_buf)
934 				free(subj_buf);
935 
936 			subj_buf=rfc822_display_hdrvalue_tobuf(h.header,
937 							       h.value,
938 							       sqwebmail_content_charset,
939 							       NULL, NULL);
940 			if (subj_buf)
941 				subj_buf=strdup(subj_buf);
942 
943 			if (subj_buf)
944 				cgi_put("headersubject", subj_buf);
945 		}
946 	}
947 	rfc822hdr_free(&h);
948 	if (event_time_list_cnt)
949 	{
950 		struct PCP_event_time *list1;
951 		struct PCP_event_time_list *p;
952 
953 		list1=malloc(sizeof(struct PCP_event_time_list)
954 			     *event_time_list_cnt);
955 		if (!list1)
956 		{
957 			sqpcp_eventend();
958 			enomem();
959 			return;
960 		}
961 		event_time_list_cnt=0;
962 		while ((p=event_time_listp) != NULL)
963 		{
964 			list1[event_time_list_cnt]=p->t;
965 			++event_time_list_cnt;
966 			event_time_listp=p->next;
967 			free(p);
968 		}
969 
970 		event_time_list=list1;
971 		n_event_time_list=event_time_list_cnt;
972 	}
973 }
974 
sqpcp_eventend()975 void sqpcp_eventend()
976 {
977 	struct my_participant *m;
978 
979 	while ((m=my_participant_list) != NULL)
980 	{
981 		my_participant_list=m->next;
982 		if (m->name)
983 			free(m->name);
984 		if (m->address)
985 			free(m->address);
986 		free(m);
987 	}
988 
989 	if (event_time_list)
990 		free(event_time_list);
991 	event_time_list=NULL;
992 	n_event_time_list=0;
993 
994 }
995 
sqpcp_eventtimes()996 void sqpcp_eventtimes()
997 {
998 	char buffer[512];
999 	unsigned i;
1000 
1001 	for (i=0; i<n_event_time_list; i++)
1002 	{
1003 		if (i)
1004 			printf("<br />\n");
1005 		if (pcp_fmttimerange(buffer, sizeof(buffer),
1006 				     event_time_list[i].start,
1007 				     event_time_list[i].end))
1008 			continue;
1009 		printf("<span class=\"tt\">");
1010 		print_safe(buffer);
1011 		printf("&nbsp;&nbsp;</span><a href=\"");
1012 		output_scriptptrget();
1013 		printf("&amp;form=newevent&amp;draftmessage=");
1014 		output_urlencoded(cgi("draftmessage"));
1015 		printf("&amp;do.deleventtime=%s-%s\"><font size=\"-2\">"
1016 		       "(%s)</font></a>",
1017 		       libmail_str_time_t(event_time_list[i].start, buffer),
1018 		       libmail_str_time_t(event_time_list[i].end, buffer+NUMBUFSIZE),
1019 		       getarg("REMOVE")
1020 		       );
1021 	}
1022 }
1023 
save_participant_names(const char * addr,const char * name,void * vp)1024 static int save_participant_names(const char *addr, const char *name,
1025 				  void *vp)
1026 {
1027 	struct my_participant *p=(struct my_participant *)vp;
1028 
1029 	for ( ; name && p; p=p->next)
1030 		if (strcasecmp(p->address, addr) == 0 && p->name == 0)
1031 			p->name=strdup(name);
1032 	return (0);
1033 }
1034 
sqpcp_eventparticipants()1035 void sqpcp_eventparticipants()
1036 {
1037 	struct my_participant *m;
1038 
1039 	if (!my_participant_list)
1040 		return;
1041 
1042 	(void)ab_get_nameaddr(save_participant_names, my_participant_list);
1043 
1044 	printf("<table border=\"0\">");
1045 
1046 	for (m=my_participant_list; m; m=m->next)
1047 	{
1048 		printf("<tr><td><span class=\"tt\">");
1049 		if (m->address)
1050 			ab_nameaddr_show(m->name, m->address);
1051 
1052 		printf("</span></td><td>&nbsp;&nbsp;<a href=\"");
1053 
1054 		output_scriptptrget();
1055 		printf("&amp;form=newevent&amp;draftmessage=");
1056 		output_urlencoded(cgi("draftmessage"));
1057 		printf("&amp;do.delparticipant=");
1058 		output_urlencoded(m->address);
1059 		printf("\"><font size=\"-2\">(%s)</font></a></td></tr>\n",
1060 		       getarg("REMOVE"));
1061 	}
1062 	printf("</table>");
1063 }
1064 
sqpcp_eventfrom()1065 void sqpcp_eventfrom()
1066 {
1067 	if (auth_getoptionenvint("wbnochangingfrom"))
1068 	{
1069 		printf("<span class=\"tt\">");
1070 		print_safe(login_fromhdr());
1071 		printf("</span>");
1072 	}
1073 	else
1074 	{
1075 		const char *p=cgi("headerfrom");
1076 
1077 		if (!p || !*p)
1078 			p=pref_from;
1079 		if (!p || !*p)
1080 			p=login_fromhdr();
1081 		if (!p)
1082 			p="";
1083 
1084 		printf("<input type=\"text\" name=\"headerfrom\" size=\"60\" value=\"");
1085 		output_attrencoded(p);
1086 		printf("\" />");
1087 	}
1088 }
1089 
sqpcp_eventtext()1090 void sqpcp_eventtext()
1091 {
1092 	const char *p;
1093 
1094 	printf("<textarea name=\"message\" cols=\"%d\" rows=\"15\" wrap=\"soft\">",
1095 	       MYLINESIZE);
1096 	p=cgi("draftmessage");
1097 
1098 	if (p && *p)
1099 	{
1100 		FILE *fp=openoldfp(p, NULL);
1101 		int dummy;
1102 
1103 		if (fp)
1104 		{
1105 			newmsg_showfp(fp, &dummy);
1106 		}
1107 		fclose(fp);
1108 	}
1109 	printf("</textarea>\n");
1110 }
1111 
sqpcp_eventattach()1112 void sqpcp_eventattach()
1113 {
1114 	const char *p;
1115 
1116 	p=cgi("draftmessage");
1117 
1118 	if (p && *p)
1119 	{
1120 		attachments_head(NULL, cgi("pos"), p);
1121 	}
1122 }
1123 
1124 /* ------- Display the cached event summary -------- */
1125 
1126 static void print_event_subject(char *, const char *, unsigned);
1127 static void print_event_link_url(const char *, const char *);
1128 
sqpcp_summary()1129 void sqpcp_summary()
1130 {
1131 	FILE *fp;
1132 	int cnt=0;
1133 	time_t now;
1134 	struct tm *tmptr;
1135 
1136 	if (!sqpcp_mode())
1137 		return;
1138 
1139 	if (*cgi("do.calendarlogin"))
1140 	{
1141 		const char *userid=getenv("AUTHADDR");
1142 		const char *password=cgi("password");
1143 
1144 		if (userid && password)
1145 		{
1146 			do_pcplogin(userid, password, 1);
1147 		}
1148 	}
1149 
1150 	if (sqpcp_has_groupware())
1151 	{
1152 		if (!sqpcp_loggedin())
1153 		{
1154 			insert_include("calendarlogin");
1155 			return;
1156 		}
1157 	}
1158 
1159 	time(&now);
1160 	tmptr=localtime(&now);
1161 
1162 	if (tmptr)
1163 	{
1164 		char *p=scriptptrget();
1165 		char *q=malloc(strlen(p)+200);
1166 
1167 		if (!q)
1168 		{
1169 			free(p);
1170 			enomem();
1171 		}
1172 
1173 		strcpy(q, p);
1174 		free(p);
1175 		strcat(q, "&amp;form=eventdaily&amp;clearcache=1&amp;date=");
1176 		sprintf(q+strlen(q), "%04d%02d%02d",
1177 			tmptr->tm_year + 1900,
1178 			tmptr->tm_mon+1,
1179 			tmptr->tm_mday);
1180 
1181 		printf(getarg("CALENDAR"), q);
1182 		free(q);
1183 	}
1184 
1185 	printf("<table class=\"eventsummary\" width=\"100%%\">");
1186 
1187 	if ((fp=fopen(CACHE, "r")) != NULL)
1188 	{
1189 		char buffer[BUFSIZ];
1190 		int i;
1191 		char last_date[256];
1192 		char date[256];
1193 		char date2[256];
1194 		struct tm *tm;
1195 		char yyyymmdd[100];
1196 
1197 		char time1[128];
1198 		char time2[128];
1199 
1200 		last_date[0]=0;
1201 
1202 		for (;;)
1203 		{
1204 			int c;
1205 			struct cacherecord cr;
1206 
1207 			i=0;
1208 
1209 			while ((c=getc(fp)) != EOF && c != '\n')
1210 			{
1211 				if (i < sizeof(buffer)-1)
1212 					buffer[i++]=(char)c;
1213 			}
1214 			buffer[i]=0;
1215 			if (i == 0 && c == EOF)
1216 				break;
1217 
1218 			parsecache_rec(buffer, &cr);
1219 
1220 			if (pcp_fmttime(date, sizeof(date),
1221 					cr.start, FMTTIME_DATE))
1222 				continue;
1223 			if (pcp_fmttime(date2, sizeof(date2),
1224 					cr.end, FMTTIME_DATE))
1225 				continue;
1226 
1227 			if (pcp_fmttime(time1, sizeof(time1),
1228 					cr.start,
1229 					FMTTIME_TIME))
1230 				continue;
1231 
1232 			if (pcp_fmttime(time2,
1233 					sizeof(time2),
1234 					cr.end,
1235 					FMTTIME_TIME))
1236 				continue;
1237 
1238 			tm=localtime(&cr.start);
1239 			if (!tm)
1240 				continue;
1241 			sprintf(yyyymmdd, "%04d%02d%02d",
1242 				tm->tm_year + 1900,
1243 				tm->tm_mon + 1,
1244 				tm->tm_mday);
1245 
1246 			i=0;
1247 			if (last_date[0] && strcmp(last_date, date) == 0)
1248 			{
1249 				if (strcmp(last_date, date2) == 0)
1250 				{
1251 					/* Same day as last event */
1252 
1253 					printf("<tr><td align=\"left\" width=\"1%%\">&nbsp;</td>"
1254 					       "<td align=\"left\">&nbsp;"
1255 					       "<a href=\"");
1256 					print_event_link_url(cr.eventid, "");
1257 					printf("&amp;date=%s\">", yyyymmdd);
1258 					print_safe(time1);
1259 					printf("&nbsp;-&nbsp;");
1260 					print_safe(time2);
1261 					printf("</a></td>");
1262 					i=1;
1263 				}
1264 				else
1265 				{
1266 					last_date[0]=0;
1267 				}
1268 			}
1269 			else
1270 			{
1271 				last_date[0]=0;
1272 				if (strcmp(date, date2) == 0)
1273 					strcpy(last_date, date);
1274 			}
1275 
1276 			if (!i)
1277 			{
1278 				if (cnt)
1279 					printf("<tr><td style=\"line-height: 0px; font-size: 8px\" colspan=\"3\">"
1280 					       "&nbsp;"
1281 					       "</td></tr>\n");
1282 				if (strcmp(date, date2))
1283 				{
1284 					printf("<tr><td colspan=\"2\">"
1285 					       "<a href=\"");
1286 					print_event_link_url(cr.eventid, "");
1287 					printf("&amp;date=%s\">", yyyymmdd);
1288 					print_safe(date);
1289 					printf("&nbsp;");
1290 					print_safe(time1);
1291 					printf("&nbsp;-&nbsp;");
1292 					print_safe(date2);
1293 					printf("&nbsp;");
1294 					print_safe(time2);
1295 					printf("</a></td>");
1296 				}
1297 				else
1298 				{
1299 					printf("<tr><td width=\"1%%\">"
1300 					       "<a href=\"");
1301 					print_event_link_url(cr.eventid, "");
1302 					printf("&amp;date=%s\">", yyyymmdd);
1303 					print_safe(date);
1304 					printf("</a></td><td>&nbsp;"
1305 					       "<a href=\"");
1306 					print_event_link_url(cr.eventid, "");
1307 					printf("&amp;date=%s\">", yyyymmdd);
1308 					print_safe(time1);
1309 					printf("&nbsp;-&nbsp;");
1310 					print_safe(time2);
1311 					printf("</a></td>");
1312 				}
1313 			}
1314 
1315 			printf("<td width=\"100%%\">"
1316 			       "<a href=\"");
1317 			print_event_link_url(cr.eventid, "");
1318 			printf("&amp;date=%s\">&nbsp;&nbsp;", yyyymmdd);
1319 			print_event_subject(cr.flags, cr.subject, 60);
1320 			printf("</a></td></tr>\n");
1321 			++cnt;
1322 		}
1323 		fclose(fp);
1324 	}
1325 
1326 	if (cnt == 0)
1327 	{
1328 		printf("<tr><td align=\"center\">%s</td></tr>\n",
1329 		       getarg("NOEVENTS"));
1330 	}
1331 
1332 	printf("</table>\n");
1333 	printf("<a href=\"");
1334 	output_scriptptrget();
1335 	printf("&amp;form=newevent\">%s</a>", getarg("NEWEVENT"));
1336 }
1337 
1338 
print_event_subject(char * flags,const char * subject,unsigned w)1339 static void print_event_subject(char *flags, const char *subject, unsigned w)
1340 {
1341 	unsigned i;
1342 	char *p;
1343 
1344 	/* Print event flags first: CANCELLED... */
1345 
1346 	for (p=flags; p && (p=strtok(p, " \t\r")) != 0; p=0)
1347 	{
1348 		printf("%s", getarg(p));
1349 	}
1350 
1351 	p=rfc822_display_hdrvalue_tobuf("subject",
1352 					subject ? subject:"",
1353 					sqwebmail_content_charset,
1354 					NULL,
1355 					NULL);
1356 
1357 	if (!p)
1358 		p=strdup(subject ? subject:"");
1359 
1360 	if (!p)
1361 		return;
1362 
1363 	if (strlen(p) > w)
1364 	{
1365 		/* Truncate long subject lines */
1366 		i=w-5;
1367 		while (i)
1368 		{
1369 			if (isspace((int)(unsigned char) p[i]))
1370 			{
1371 				strcpy(p+i, "...");
1372 				break;
1373 			}
1374 			--i;
1375 		}
1376 	}
1377 	print_safe(p);
1378 	free(p);
1379 }
1380 
1381 /* ------- New event support code -------- */
1382 
1383 static int addtime(int);
1384 static void addparticipant(int, const char *);
1385 
openoldfp(const char * p,unsigned long * prev_size)1386 static FILE *openoldfp(const char *p, unsigned long *prev_size)
1387 {
1388 	struct stat stat_buf;
1389 	char *filename;
1390 	int x;
1391 	FILE *oldfp;
1392 
1393 	CHECKFILENAME(p);
1394 
1395 	filename=maildir_find(INBOX "." DRAFTS, p);
1396 	if (!filename)
1397 		return (NULL);
1398 
1399 	x=maildir_safeopen(filename, O_RDONLY, 0);
1400 	free(filename);
1401 	if (x < 0)
1402 		return (NULL);
1403 
1404 
1405 	if (fstat(x, &stat_buf) < 0 || (oldfp=fdopen(x, "r")) == NULL)
1406 	{
1407 		close(x);
1408 		return (NULL);
1409 	}
1410 
1411 	if (prev_size)
1412 		*prev_size=stat_buf.st_size;
1413 	return (oldfp);
1414 }
1415 
1416 
1417 /* ------------- Conflict indicators ---------------- */
1418 
1419 struct conflict_list {
1420 	struct conflict_list *next;
1421 	char *event_id;
1422 	time_t start, end;
1423 	char *address;
1424 	char *subject;
1425 } ;
1426 
1427 static struct conflict_list *conflict_list=NULL;
1428 
init_save_conflict()1429 static void init_save_conflict()
1430 {
1431 	while (conflict_list)
1432 	{
1433 		struct conflict_list *p=conflict_list;
1434 
1435 		conflict_list=p->next;
1436 		if (p->event_id)
1437 			free(p->event_id);
1438 		if (p->address)
1439 			free(p->address);
1440 		if (p->subject)
1441 			free(p->subject);
1442 		free(p);
1443 	}
1444 }
1445 
save_conflict(const char * event_id,time_t start,time_t end,const char * address,void * dummy)1446 static int save_conflict(const char *event_id, time_t start, time_t end,
1447 			  const char *address,
1448 			  void *dummy)
1449 {
1450 	struct conflict_list *p, **ptr;
1451 
1452 	for (ptr= &conflict_list; *ptr; ptr=&(*ptr)->next)
1453 	{
1454 		if ( (*ptr)->end > end)
1455 			break;
1456 	}
1457 
1458 	if ((p=malloc(sizeof(struct conflict_list))) == NULL)
1459 		return (-1);
1460 	memset(p, 0, sizeof(*p));
1461 	p->next= *ptr;
1462 	*ptr=p;
1463 
1464 	p->start=start;
1465 	p->end=end;
1466 	if ((p->event_id=strdup(event_id)) == NULL ||
1467 	    (address && (p->address=strdup(address)) == NULL))
1468 		return (-1);
1469 
1470 	return (0);
1471 }
1472 
1473 static int save_conflict_subj(struct PCP_retr *, const char *,
1474 			      const char *, void *);
1475 
show_conflict_error(struct PCP * pcp)1476 static void show_conflict_error(struct PCP *pcp)
1477 {
1478 	unsigned n;
1479 	struct conflict_list *p;
1480 	const char **l;
1481 	struct PCP_retr r;
1482 
1483 	for (n=0, p=conflict_list; p; p=p->next)
1484 		if (p->event_id && (!p->address ||
1485 				    strcmp(p->address, "@") == 0))
1486 			++n;
1487 
1488 	if ((l=malloc(sizeof(const char *)*(n+1))) == NULL)
1489 		return;
1490 
1491 	for (n=0, p=conflict_list; p; p=p->next)
1492 		if (p->event_id && (!p->address ||
1493 				    strcmp(p->address, "@") == 0))
1494 		{
1495 			l[n]=p->event_id;
1496 			++n;
1497 		}
1498 
1499 	l[n]=0;
1500 	memset(&r, 0, sizeof(r));
1501 	r.event_id_list=l;
1502 	r.callback_headers_func=save_conflict_subj;
1503 
1504 	if (n == 0 || pcp_retr(pcp, &r) == 0)
1505 	{
1506 		printf("<table border=\"0\" width=\"100%%\" class=\"small-error\">");
1507 		for (p=conflict_list; p; p=p->next)
1508 		{
1509 			char buffer[512];
1510 
1511 			printf("<tr><td width=\"30\">&nbsp;</td><td><span class=\"tt\">");
1512 			if (pcp_fmttimerange(buffer, sizeof(buffer),
1513 					     p->start,
1514 					     p->end) == 0)
1515 			{
1516 				print_safe(buffer);
1517 			}
1518 			printf("</span></td><td width=\"30\">&nbsp;</td><td width=\"100%%\"><span class=\"tt\">");
1519 			if (p->address && strcmp(p->address, "@"))
1520 			{
1521 				printf("%s", getarg("CONFLICTERR2"));
1522 				print_safe(p->address);
1523 			}
1524 			else
1525 				print_event_subject("", p->subject
1526 						    ? p->subject:"", 60);
1527 			printf("</span></td></tr>\n");
1528 		}
1529 		printf("<tr><td colspan=\"4\"><hr width=\"90%%\" /></td></tr></table>\n");
1530 	}
1531 	free(l);
1532 	init_save_conflict();
1533 }
1534 
save_conflict_subj(struct PCP_retr * r,const char * h,const char * v,void * dummy)1535 static int save_conflict_subj(struct PCP_retr *r, const char *h,
1536 			      const char *v, void *dummy)
1537 {
1538 	struct conflict_list *p;
1539 
1540 	if (strcasecmp(h, "subject") || !v)
1541 		return (0);
1542 
1543 	for (p=conflict_list; p; p=p->next)
1544 		if (p->event_id && strcmp(p->event_id, r->event_id) == 0)
1545 		{
1546 			if (p->subject)
1547 				free(p->subject);
1548 			if ((p->subject=strdup(v)) != NULL)
1549 				collapse_subject(p->subject);
1550 			break;
1551 		}
1552 	return (0);
1553 }
1554 
1555 /* -------------------------------------------------- */
1556 
showerror()1557 static void showerror()
1558 {
1559 	const char *p;
1560 
1561 	p=cgi("error");
1562 	if (strcmp(p, "quota") == 0)
1563 		printf("%s", getarg("QUOTAERR"));
1564 	if (strcmp(p, "time") == 0)
1565 		printf("%s", getarg("NOTIMEERR"));
1566 	if (strcmp(p, "conflict") == 0)
1567 	{
1568 		struct PCP *pcp=sqpcp_calendar();
1569 
1570 		printf("%s", getarg("CONFLICTERR"));
1571 		if (pcp)
1572 			show_conflict_error(pcp);
1573 	}
1574 	if (strcmp(p, "calendar") == 0)
1575 	{
1576 		printf(getarg("CALENDARERR"), cgi("pcperror"));
1577 	}
1578 	if (strcmp(p, "locked") == 0)
1579 		printf("%s", getarg("LOCKERR"));
1580 	if (strcmp(p, "notfound") == 0)
1581 		printf("%s", getarg("NOTFOUNDERR"));
1582 	if (strcmp(p, "eventlocked") == 0)
1583 		printf("%s", getarg("EVENTLOCKEDERR"));
1584 }
1585 
1586 #if 0
1587 /*
1588 ** Create/Estimate the To: header which lists event participants.
1589 */
1590 
1591 static void mktohdr(char *h, size_t *sizep)
1592 {
1593 	int need_toh=1;
1594 	size_t l=0;
1595 	struct my_participant *p;
1596 
1597 	*sizep=4;
1598 
1599 	for (p=my_participant_list; p; p=p->next)
1600 	{
1601 		const char *c;
1602 
1603 		if (*sizep - l > 500)
1604 		{
1605 			if (h)
1606 				*h++='\n';
1607 			++*sizep;
1608 			need_toh=1;
1609 			l= *sizep;
1610 		}
1611 
1612 		if (need_toh)
1613 		{
1614 			if (h)
1615 			{
1616 				strcpy(h, "To: ");
1617 				h += 4;
1618 			}
1619 			*sizep += 4;
1620 			need_toh=0;
1621 		}
1622 		else
1623 		{
1624 			if (h)
1625 			{
1626 				strcpy(h, ",\n  ");
1627 				h += 4;
1628 			}
1629 			*sizep += 4;
1630 		}
1631 
1632 		if (p->name && *p->name)
1633 		{
1634 			if (h)
1635 				*h++='"';
1636 			++*sizep;
1637 
1638 			for (c=p->name; *c; c++)
1639 			{
1640 				if (*c == '"' || *c == '\\')
1641 				{
1642 					if (h)
1643 						*h++ = '\\';
1644 					++*sizep;
1645 				}
1646 				if (h)
1647 					*h++ = *c;
1648 				++*sizep;
1649 			}
1650 
1651 			if (h)
1652 			{
1653 				*h++='"';
1654 				*h++=' ';
1655 			}
1656 			*sizep += 2;
1657 		}
1658 
1659 		if (h)
1660 			*h++='<';
1661 		++*sizep;
1662 
1663 		for (c=p->address; *c; c++)
1664 		{
1665 			if (h)
1666 				*h++= *c;
1667 			++*sizep;
1668 		}
1669 		if (h)
1670 			*h++='>';
1671 		++*sizep;
1672 	}
1673 
1674 	if (my_participant_list)
1675 	{
1676 		if (h)
1677 			*h++='\n';
1678 		++*sizep;
1679 	}
1680 
1681 	if (h)
1682 		*h++=0;
1683 	++*sizep;
1684 }
1685 #endif
1686 
sqpcp_newevent()1687 void sqpcp_newevent()
1688 {
1689 	char *draftfilename;
1690 	int newdraftfd;
1691 	const char *p;
1692 	unsigned long prev_size=0;
1693 	FILE *oldfp=NULL;
1694 	int errflag=0;
1695 	int do_newevent= *cgi("do.neweventtime") ? 1:0;
1696 	int do_newparticipant= *cgi("do.addparticipant") ? 1:0;
1697 	int do_delevent=0;
1698 	int do_delparticipant= *cgi("do.delparticipant") ? 1:0;
1699 	time_t delstart=0, delend=0;
1700 
1701 	static char *draftmessage_buf=0;
1702 
1703 	showerror();
1704 
1705 	if (!do_newevent)
1706 	{
1707 		if ((p=cgi("do.deleventtime")) && *p)
1708 		{
1709 			unsigned long a, b;
1710 
1711 			if (sscanf(p, "%lu-%lu", &a, &b) == 2)
1712 			{
1713 				delstart=(time_t)a;
1714 				delend=(time_t)b;
1715 				do_delevent=1;
1716 			}
1717 		}
1718 	}
1719 
1720 	p=cgi("draftmessage");
1721 
1722 	if (!do_newevent && !do_delevent && !do_newparticipant
1723 	    && !do_delparticipant)
1724 	{
1725 		if (*cgi("do.neweventpreview") && p && *p)
1726 		{
1727 			printf("<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"1\" class=\"box-small-outer\"><tr><td>\n");
1728 			printf("<table width=\"100%%\" border=\"0\" cellspacing=\"0\" cellpadding=\"4\" class=\"preview\"><tr><td>\n");
1729 			newmsg_preview(p);
1730 			printf("</td></tr></table>\n");
1731 			printf("</td></tr></table>\n");
1732 		}
1733 		return;
1734 	}
1735 
1736 	if (p && *p)
1737 	{
1738 		oldfp=openoldfp(p, &prev_size);
1739 		if (!oldfp)
1740 			p="";
1741 	}
1742 
1743 	if (p && *p)
1744 	{
1745 		newdraftfd=maildir_recreatemsg(INBOX "." DRAFTS, p, &draftfilename);
1746 	}
1747 	else
1748 	{
1749 		newdraftfd=maildir_createmsg(INBOX "." DRAFTS, 0, &draftfilename);
1750 		maildir_writemsgstr(newdraftfd, "X-Event: 1\n");
1751 
1752 		if (draftmessage_buf)
1753 			free(draftmessage_buf);
1754 		if ((draftmessage_buf=strdup(draftfilename)) != 0)
1755 			cgi_put("draftmessage", draftmessage_buf);
1756 	}
1757 
1758 	if (do_newevent || do_delevent || do_newparticipant
1759 	    || do_delparticipant)
1760 	{
1761 		if (oldfp)
1762 		{
1763 			struct rfc822hdr h;
1764 
1765 			rfc822hdr_init(&h, 8192);
1766 			while (rfc822hdr_read(&h, oldfp, NULL, 0) == 0)
1767 			{
1768 				unsigned long a, b;
1769 				if (do_delevent && strcasecmp(h.header,
1770 							      "X-Event-Time")
1771 				    == 0 && h.value && sscanf(h.value,
1772 							      "%lu %lu",
1773 							      &a, &b) == 2)
1774 
1775 				{
1776 					if ( (time_t)a == delstart &&
1777 					     (time_t)b == delend)
1778 						continue;
1779 				}
1780 
1781 				if (do_delparticipant
1782 				    && strcasecmp(h.header, "X-Event-Participant")
1783 				    == 0 && h.value)
1784 				{
1785 					if (strcmp(h.value,
1786 						   cgi("do.delparticipant"))
1787 					    == 0)
1788 						continue;
1789 				}
1790 				if (strcasecmp(h.header,
1791 					       "X-Event-Participant") == 0 &&
1792 				    h.value)
1793 					add_my_participant(h.value);
1794 
1795 				if (strcasecmp(h.header, "To") == 0)
1796 					continue;
1797 				/* To: header rebuilt later */
1798 
1799 				maildir_writemsgstr(newdraftfd, h.header);
1800 				maildir_writemsgstr(newdraftfd, ": ");
1801 				maildir_writemsgstr(newdraftfd, h.value);
1802 				maildir_writemsgstr(newdraftfd, "\n");
1803 			}
1804 			rfc822hdr_free(&h);
1805 
1806 		}
1807 
1808 		if (do_newevent && addtime(newdraftfd))
1809 		{
1810 			errflag=1;
1811 			printf("%s", getarg("TIMEERR"));
1812 		}
1813 
1814 		if (do_newparticipant)
1815 		{
1816 			const char *p=cgi("addressbookname");
1817 
1818 			if (!*p)
1819 				p=cgi("participant1");
1820 
1821 			addparticipant(newdraftfd, p);
1822 		}
1823 
1824 		(void)ab_get_nameaddr(save_participant_names,
1825 				      my_participant_list);
1826 
1827 #if 0
1828 		{
1829 			struct rfc822t *t;
1830 			struct rfc822a *a;
1831 			char *p;
1832 			char *tohdr;
1833 			size_t tohdr_size;
1834 
1835 			mktohdr(NULL, &tohdr_size);
1836 
1837 			tohdr=malloc(tohdr_size);
1838 			if (!tohdr)
1839 				enomem();
1840 
1841 			mktohdr(tohdr, &tohdr_size);
1842 
1843 			if ((t=rfc822t_alloc_new(tohdr, NULL, NULL)) == NULL)
1844 			{
1845 				free(tohdr);
1846 				enomem();
1847 			}
1848 
1849 			if ((a=rfc822a_alloc(t)) == NULL)
1850 			{
1851 				rfc822t_free(t);
1852 				free(tohdr);
1853 				enomem();
1854 			}
1855 
1856 			p=rfc2047_encode_header(a,sqwebmail_content_charset);
1857 
1858 			if (!p)
1859 			{
1860 				rfc822a_free(a);
1861 				rfc822t_free(t);
1862 				free(tohdr);
1863 				enomem();
1864 			}
1865 			free(tohdr);
1866 			tohdr=p;
1867 			rfc822a_free(a);
1868 			rfc822t_free(t);
1869 
1870 			maildir_writemsgstr(newdraftfd, tohdr);
1871 			maildir_writemsgstr(newdraftfd, "\n");
1872 			free(tohdr);
1873 		}
1874 #endif
1875 
1876 		sqpcp_eventend(); /* Deallocate participant list */
1877 
1878 		maildir_writemsgstr(newdraftfd, "\n");
1879 	}
1880 
1881 	if (oldfp)
1882 	{
1883 		char buf[BUFSIZ];
1884 		int n;
1885 
1886 		while ((n=fread(buf, 1, sizeof(buf), oldfp)) > 0)
1887 			maildir_writemsg(newdraftfd, buf, n);
1888 	}
1889 
1890 	if (oldfp)
1891 		fclose(oldfp);
1892 
1893 	if (errflag)
1894 	{
1895 		maildir_deletenewmsg(newdraftfd, INBOX "." DRAFTS, draftfilename);
1896 	}
1897 	else if (maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, 1,
1898 				  prev_size))
1899 	{
1900 		printf("%s", getarg("QUOTAERR"));
1901 	}
1902 
1903 	free(draftfilename);
1904 }
1905 
1906 /* Split apart date/time string into space-separated words */
1907 
mkargv(char * p,int * argc)1908 static char **mkargv(char *p, int *argc)
1909 {
1910 	int pass;
1911 	char **argv=0;
1912 	char *q;
1913 
1914 	/* Two passes - count words, then make them */
1915 
1916 	for (pass=0; pass<2; pass++)
1917 	{
1918 		if (pass)
1919 		{
1920 			if ((argv=malloc(sizeof(char *)* (*argc+1))) == NULL)
1921 				return (NULL);
1922 		}
1923 		*argc=0;
1924 
1925 		for (q=p; *q; )
1926 		{
1927 			if (isspace((int)(unsigned char)*q))
1928 			{
1929 				++q;
1930 				continue;	/* Skip leading space */
1931 			}
1932 
1933 			if (pass)
1934 				argv[ *argc ] = q;
1935 			++*argc;
1936 
1937 			while (*q)	/* Look for next space */
1938 			{
1939 				if (isspace((int)(unsigned char)*q))
1940 				{
1941 					if (pass)
1942 						*q=0;
1943 					++q;
1944 					break;
1945 				}
1946 				++q;
1947 			}
1948 		}
1949 	}
1950 	argv[ *argc ] = 0;
1951 	return (argv);
1952 }
1953 
1954 static int savetime(time_t, time_t, void *);
1955 
addtime(int newdraftfd)1956 static int addtime(int newdraftfd)
1957 {
1958 	struct pcp_parse_datetime_info pdi;
1959 	char *t_buf;
1960 	char **t_argv;
1961 	time_t starttime, endtime;
1962 	int argn, argc;
1963 	int h, m;
1964 
1965 	pdi.today_name=cgi("today");		/* Locale string */
1966 	pdi.tomorrow_name=cgi("tomorrow");	/* Locale string */
1967 
1968 	t_buf=strdup(cgi("starttime"));
1969 	if (!t_buf)
1970 		return (-1);
1971 	t_argv=mkargv(t_buf, &argc);
1972 	if (!t_argv)
1973 	{
1974 		free(t_buf);
1975 		return (-1);
1976 	}
1977 
1978 	argn=0;
1979 	starttime=pcp_parse_datetime(&argn, argc, t_argv, &pdi);
1980 	free(t_argv);
1981 	free(t_buf);
1982 	if (!starttime)
1983 		return (-1);
1984 	h=atoi(cgi("hours"));
1985 	m=atoi(cgi("mins"));
1986 	if (h < 0 || m < 0 || h > 999 || m > 59)
1987 		return (-1);
1988 
1989 	endtime=starttime + h * 60 * 60 + m * 60;
1990 
1991 	argn=0;
1992 	t_buf=strdup(cgi("endtime"));
1993 	if (!t_buf)
1994 		return (-1);
1995 	t_argv=mkargv(t_buf, &argc);
1996 	if (!t_argv)
1997 	{
1998 		free(t_buf);
1999 		return (-1);
2000 	}
2001 
2002 	if (argc == 0)	/* Not a weekly event */
2003 	{
2004 		savetime(starttime, endtime, &newdraftfd);
2005 	}
2006 	else
2007 	{
2008 		if (pcp_parse_datetime_until(starttime, endtime, &argn, argc,
2009 					     t_argv,
2010 					     atoi(cgi("recurring")),
2011 					     savetime, &newdraftfd))
2012 		{
2013 			free(t_argv);
2014 			free(t_buf);
2015 			return (-1);
2016 		}
2017 	}
2018 	free(t_argv);
2019 	free(t_buf);
2020 	return (0);
2021 }
2022 
savetime(time_t from,time_t to,void * dummy)2023 static int savetime(time_t from, time_t to, void *dummy)
2024 {
2025 	char buf[NUMBUFSIZE];
2026 	int fd= *(int *)dummy;
2027 
2028 	maildir_writemsgstr(fd, "X-Event-Time: ");
2029 	maildir_writemsgstr(fd, libmail_str_time_t(from, buf));
2030 	maildir_writemsgstr(fd, " ");
2031 	maildir_writemsgstr(fd, libmail_str_time_t(to, buf));
2032 	maildir_writemsgstr(fd, "\n");
2033 	return (0);
2034 }
2035 
addparticipant(int fd,const char * n)2036 static void addparticipant(int fd, const char *n)
2037 {
2038 	char *nn, *p, *q;
2039 
2040 	const char *domain;
2041 
2042 	domain=getenv("AUTHADDR");
2043 
2044 	if (domain)
2045 		domain=strrchr(domain, '@');
2046 
2047 	if (domain)
2048 		++domain;
2049 	else
2050 		domain=myhostname();
2051 
2052 	while (n && isspace((int)(unsigned char)*n))
2053 		++n;
2054 
2055 	if (!n || !*n)
2056 		return;
2057 
2058 	if (strchr(n, '\n') || strchr(n, '\r'))
2059 		return;
2060 
2061 	if ((nn=malloc(strlen(n)+strlen(domain)+2)) == NULL)
2062 		enomem();
2063 
2064 	strcpy(nn, n);
2065 
2066 	for (p=q=nn; *p; p++)
2067 		if (!isspace((int)(unsigned char)*p))
2068 			q=p+1;
2069 	*q=0;
2070 
2071 	if (strchr(nn, '@') == 0)
2072 		strcat(strcat(nn, "@"), domain);
2073 
2074 
2075 	maildir_writemsgstr(fd, "X-Event-Participant: ");
2076 	maildir_writemsgstr(fd, nn);
2077 	maildir_writemsgstr(fd, "\n");
2078 	add_my_participant(nn);
2079 	free(nn);
2080 }
2081 
2082 /* ------------- Save text ------------- */
2083 
savedraft()2084 static char *savedraft()
2085 {
2086 	const char *p=cgi("draftmessage");
2087 	char *msg, *filename;
2088 
2089 	if (p && *p)
2090 	{
2091 		CHECKFILENAME(p);
2092 	}
2093 
2094 	filename=p && *p ? maildir_find(INBOX "." DRAFTS, p):NULL;
2095 
2096 	msg=newmsg_createdraft_do(filename, cgi("message"), NEWMSG_PCP);
2097 	if (filename)
2098 		free(filename);
2099 
2100 	if (!msg)
2101 		enomem();
2102 	return (msg);
2103 }
2104 
previewdraft(char * msg,void (* func)(const char *))2105 static void previewdraft(char *msg, void (*func)(const char *))
2106 {
2107 	char *msg2, *msg2p;
2108 
2109 	msg2=maildir_find(INBOX "." DRAFTS, msg);
2110 	free(msg);
2111 	if (!msg2)
2112 		enomem();
2113 	if ((msg2p=strrchr(msg2, '/')) != 0)
2114 		++msg2p;
2115 	else
2116 		msg2p=msg2;
2117 
2118 	cgi_put("draftmessage", msg2p);
2119 	if (func)
2120 		(*func)(msg2p);
2121 	output_form("newevent.html");
2122 	free(msg2);
2123 }
2124 
sqpcp_preview()2125 void sqpcp_preview()
2126 {
2127 	char *msg;
2128 
2129 	msg=savedraft();
2130 	previewdraft(msg, NULL);
2131 }
2132 
sqpcp_postpone()2133 void sqpcp_postpone()
2134 {
2135 	char *msg;
2136 
2137 	msg=savedraft();
2138 	free(msg);
2139 	output_form("folders.html");
2140 }
2141 
2142 static void deleteattach(const char *);
2143 
sqpcp_deleteattach()2144 void sqpcp_deleteattach()
2145 {
2146 	char *msg;
2147 
2148 	msg=savedraft();
2149 	previewdraft(msg, deleteattach);
2150 }
2151 
deleteattach(const char * msg)2152 static void deleteattach(const char *msg)
2153 {
2154 	attach_delete(msg);
2155 }
2156 
2157 static void doupload(const char *);
2158 
sqpcp_uploadattach()2159 void sqpcp_uploadattach()
2160 {
2161 	char *msg;
2162 
2163 	msg=savedraft();
2164 	previewdraft(msg, doupload);
2165 }
2166 
doupload(const char * msg)2167 static void doupload(const char *msg)
2168 {
2169 	int flag;
2170 
2171 	flag=attach_upload(msg, NULL, NULL);
2172 
2173 	if (flag)
2174 		cgi_put("error", "quota");
2175 }
2176 
2177 
sqpcp_attachpubkey()2178 void sqpcp_attachpubkey()
2179 {
2180 	char *msg;
2181 
2182 	msg=savedraft();
2183 	previewdraft(msg, NULL);
2184 }
2185 
sqpcp_attachprivkey()2186 void sqpcp_attachprivkey()
2187 {
2188 	char *msg;
2189 
2190 	msg=savedraft();
2191 	previewdraft(msg, NULL);
2192 }
2193 
2194 /* ---------------- Save event ------------------ */
2195 
2196 struct participant_list {
2197 	struct participant_list *next;
2198 	char *address;
2199 } ;
2200 
2201 struct saveinfo {
2202 	struct PCP_event_time *times;
2203 	unsigned n_times;
2204 	struct PCP_event_participant *participants;
2205 	unsigned n_participants;
2206 	struct participant_list *participant_list;
2207 
2208 	char *old_eventid;
2209 } ;
2210 
init_saveinfo(struct saveinfo * si,FILE * fp)2211 static int init_saveinfo(struct saveinfo *si, FILE *fp)
2212 {
2213 	struct rfc822hdr h;
2214 
2215 	struct savetimelist {
2216 		struct savetimelist *next;
2217 		struct PCP_event_time event_time;
2218 	} *tlist=NULL, *p;
2219 	unsigned tcnt=0;
2220 	struct participant_list *l;
2221 
2222 
2223 	si->times=NULL;
2224 	si->n_times=0;
2225 	si->old_eventid=0;
2226 	si->participants=NULL;
2227 	si->n_participants=0;
2228 	si->participant_list=NULL;
2229 
2230 	rfc822hdr_init(&h, BUFSIZ);
2231 	while (rfc822hdr_read(&h, fp, NULL, 0) == 0)
2232 	{
2233 		unsigned long a, b;
2234 
2235 		if (strcasecmp(h.header, "X-Event-Participant") == 0 && h.value)
2236 		{
2237 			l=malloc(sizeof(struct participant_list));
2238 			if (!l || (l->address=strdup(h.value)) == NULL)
2239 			{
2240 				if (l)
2241 					free(l);
2242 
2243 				while ((l=si->participant_list) != NULL)
2244 				{
2245 					si->participant_list=l->next;
2246 					free(l->address);
2247 					free(l);
2248 				}
2249 				while (tlist)
2250 				{
2251 					p=tlist;
2252 					tlist=p->next;
2253 					free(p);
2254 				}
2255 				rfc822hdr_free(&h);
2256 				return (-1);
2257 			}
2258 			l->next=si->participant_list;
2259 			si->participant_list=l;
2260 			++si->n_participants;
2261 		}
2262 		else if (strcasecmp(h.header, "X-Event-Time") == 0 &&
2263 			 h.value && sscanf(h.value, "%lu %lu", &a, &b) == 2)
2264 		{
2265 			if ((p=malloc(sizeof(struct savetimelist))) == NULL)
2266 			{
2267 				while ((l=si->participant_list) != NULL)
2268 				{
2269 					si->participant_list=l->next;
2270 					free(l->address);
2271 					free(l);
2272 				}
2273 				while (tlist)
2274 				{
2275 					p=tlist;
2276 					tlist=p->next;
2277 					free(p);
2278 				}
2279 				rfc822hdr_free(&h);
2280 				return (-1);
2281 			}
2282 			p->next=tlist;
2283 			tlist=p;
2284 			p->event_time.start=a;
2285 			p->event_time.end=b;
2286 			++tcnt;
2287 		}
2288 
2289 		if (strcasecmp(h.header, "X-Old-EventId") == 0 && h.value)
2290 		{
2291 			if (si->old_eventid)
2292 				free(si->old_eventid);
2293 			si->old_eventid=strdup(h.value);
2294 			if (!si->old_eventid)
2295 			{
2296 				rfc822hdr_free(&h);
2297 				return (-1);
2298 			}
2299 		}
2300 	}
2301 	rfc822hdr_free(&h);
2302 
2303 	if (si->n_participants)
2304 	{
2305 		unsigned n=0;
2306 
2307 		if ((si->participants
2308 		     =calloc(sizeof(struct PCP_event_participant),
2309 			     si->n_participants)) == NULL)
2310 		{
2311 			while ((l=si->participant_list) != NULL)
2312 			{
2313 				si->participant_list=l->next;
2314 				free(l->address);
2315 				free(l);
2316 			}
2317 			while (tlist)
2318 			{
2319 				p=tlist;
2320 				tlist=p->next;
2321 				free(p);
2322 			}
2323 			return (-1);
2324 		}
2325 
2326 		for (l=si->participant_list; l; l=l->next)
2327 		{
2328 			si->participants[n].address=l->address;
2329 			++n;
2330 		}
2331 	}
2332 
2333 	if (tcnt)
2334 	{
2335 		si->n_times=tcnt;
2336 		if ((si->times=malloc(sizeof(struct PCP_event_time)
2337 				      *tcnt)) == NULL)
2338 		{
2339 			while ((l=si->participant_list) != NULL)
2340 			{
2341 				si->participant_list=l->next;
2342 				free(l->address);
2343 				free(l);
2344 			}
2345 			while (tlist)
2346 			{
2347 				p=tlist;
2348 				tlist=p->next;
2349 				free(p);
2350 			}
2351 			if (si->old_eventid)
2352 				free(si->old_eventid);
2353 			return (-1);
2354 		}
2355 		tcnt=0;
2356 		while (tlist)
2357 		{
2358 			p=tlist;
2359 			tlist=p->next;
2360 			si->times[tcnt]=p->event_time;
2361 			free(p);
2362 			++tcnt;
2363 		}
2364 	}
2365 	return (0);
2366 }
2367 
free_saveinfo(struct saveinfo * si)2368 static void free_saveinfo(struct saveinfo *si)
2369 {
2370 	struct participant_list *l;
2371 
2372 	if (si->participants)
2373 		free(si->participants);
2374 
2375 	while ((l=si->participant_list) != NULL)
2376 	{
2377 		si->participant_list=l->next;
2378 		free(l->address);
2379 		free(l);
2380 	}
2381 
2382 	if (si->times)
2383 		free(si->times);
2384 	if (si->old_eventid)
2385 		free(si->old_eventid);
2386 }
2387 
dropquota(const char * filename,int fd)2388 static void dropquota(const char *filename, int fd)
2389 {
2390 	unsigned long filesize=0;
2391 
2392 	if (maildir_parsequota(filename, &filesize))
2393 	{
2394 		struct stat stat_buf;
2395 
2396 		if (fstat(fd, &stat_buf))
2397 			stat_buf.st_size=0;
2398 		filesize=stat_buf.st_size;
2399 	}
2400 
2401 	maildir_quota_deleted(".", (int64_t)-filesize, -1);
2402 }
2403 
2404 /* ------------------------------------------------------------------------
2405 **
2406 ** Save a calendar event
2407 ** ----------------------------------------------------------------------*/
2408 
2409 static int dosave(FILE *, struct saveinfo *);
2410 
sqpcp_save()2411 void sqpcp_save()
2412 {
2413 	char *msg, *sentmsg, *p;
2414 	FILE *fp;
2415 	struct saveinfo si;
2416 	int isgpgerr;
2417 
2418 	msg=savedraft();
2419 	if (*cgi("error"))	/* Error, go back to the screen */
2420 	{
2421 		previewdraft(msg, NULL);
2422 		return;
2423 	}
2424 
2425 	fp=openoldfp(msg, NULL);
2426 	if (!fp)
2427 	{
2428 		free(msg);
2429 		enomem();
2430 	}
2431 
2432 	if (init_saveinfo(&si, fp))
2433 	{
2434 		fclose(fp);
2435 		free(msg);
2436 		enomem();
2437 	}
2438 
2439 	if (si.times == 0)
2440 	{
2441 		fclose(fp);
2442 		cgi_put("error", "time");
2443 		previewdraft(msg, NULL);
2444 		return;
2445 	}
2446 	fclose(fp);
2447 
2448 	sentmsg=newmsg_createsentmsg(msg, &isgpgerr);
2449 
2450 	/* Immediately remove the formatted event text from the sent folder */
2451 
2452 	if (sentmsg)
2453 	{
2454 		p=maildir_find(INBOX "." SENT, sentmsg);
2455 		free(sentmsg);
2456 		sentmsg=p;
2457 	}
2458 
2459 	if (!sentmsg)
2460 	{
2461 		cgi_put("error", "quota");	/* TODO: gpgerr */
2462 		free_saveinfo(&si);
2463 		previewdraft(msg, NULL);
2464 		return;
2465 	}
2466 
2467 
2468 	fp=fopen(sentmsg, "r");
2469 	if (!fp)
2470 	{
2471 		free(sentmsg);
2472 		free(msg);
2473 		free_saveinfo(&si);
2474 		enomem();
2475 		return;
2476 	}
2477 
2478 	fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
2479 
2480 	unlink(sentmsg);
2481 	dropquota(sentmsg, fileno(fp));
2482 	free(sentmsg);
2483 
2484 	if (dosave(fp, &si))
2485 	{
2486 		fclose(fp);
2487 		free_saveinfo(&si);
2488 		previewdraft(msg, NULL);
2489 		return;
2490 	}
2491 	fclose(fp);
2492 
2493 	p=maildir_find(INBOX "." DRAFTS, msg);
2494 	free(msg);
2495 
2496 	fp=p ? fopen(p, "r"):NULL;
2497 	unlink(p);
2498 	if (fp)
2499 	{
2500 		dropquota(p, fileno(fp));
2501 		fclose(fp);
2502 	}
2503 	free(p);
2504 	free_saveinfo(&si);
2505 	output_form("folders.html");
2506 }
2507 
2508 /* With all the preliminaries out of the way, put it on the calendar */
2509 
saveerror(struct PCP * pcp,const int * xerror)2510 static void saveerror(struct PCP *pcp, const int *xerror)
2511 {
2512 	static char *errmsgbuf=0;
2513 	const char *p;
2514 
2515 	if (xerror)
2516 		switch (*xerror) {
2517 		case PCP_ERR_SYSERR:	/* Can be deliberate, see addacl() */
2518 			cgi_put("error", "calendar");
2519 			cgi_put("pcperror", strerror(errno));
2520 			return;
2521 		case PCP_ERR_LOCK:
2522 			cgi_put("error", "locked");
2523 			return;
2524 		case PCP_ERR_CONFLICT:
2525 			cgi_put("error", "conflict");
2526 			return;
2527 		case PCP_ERR_EVENTNOTFOUND:
2528 			cgi_put("error", "notfound");
2529 			return;
2530 		case PCP_ERR_EVENTLOCKED:
2531 			cgi_put("error", "eventlocked");
2532 			return;
2533 		}
2534 
2535 	cgi_put("error", "calendar");
2536 
2537 	if (errmsgbuf)
2538 		free(errmsgbuf);
2539 
2540 	/*
2541 	** Save err msg into a static buffer, because err msg text memory
2542 	** may go away after the handle is closed.
2543 	*/
2544 
2545 	p=pcp_errmsg(pcp);
2546 	errmsgbuf=strdup(p ? p:"");
2547 	cgi_put("pcperror", errmsgbuf);
2548 }
2549 
2550 struct proxy_list_entry {
2551 	struct proxy_list_entry *next;
2552 	char *userid;
2553 } ;
2554 
2555 struct proxy_update_list {
2556 	struct proxy_list_entry *new_list;
2557 	struct proxy_list_entry *delete_list;
2558 } ;
2559 
proxy_update_list_save(const char * action,const char * userid,void * voidarg)2560 static void proxy_update_list_save(const char *action,
2561 				   const char *userid,
2562 				   void *voidarg)
2563 {
2564 	struct proxy_update_list *pul=(struct proxy_update_list *)voidarg;
2565 
2566 	struct proxy_list_entry **eptr, *e;
2567 
2568 	if (strcmp(action, "NEW") == 0)
2569 		eptr= &pul->new_list;
2570 	else if (strcmp(action, "DELETE") == 0)
2571 		eptr= &pul->delete_list;
2572 	else
2573 		return;
2574 
2575 	while (*eptr && strcmp( (*eptr)->userid, userid) == 0)
2576 		eptr= &(*eptr)->next;
2577 
2578 	if ((e=malloc(sizeof(struct proxy_list_entry))) == NULL ||
2579 	    (e->userid=strdup(userid)) == NULL)
2580 	{
2581 		if (e)
2582 			free(e);
2583 		fprintf(stderr, "CRIT: out of memory.\n");
2584 		return;
2585 	}
2586 
2587 	e->next= *eptr;
2588 	*eptr=e;
2589 }
2590 
proxy_update_list_free(struct proxy_update_list * p)2591 static void proxy_update_list_free(struct proxy_update_list *p)
2592 {
2593 	struct proxy_list_entry *e;
2594 
2595 	while ((e=p->new_list) != NULL)
2596 	{
2597 		p->new_list=e->next;
2598 		free(e->userid);
2599 		free(e);
2600 	}
2601 
2602 	while ((e=p->delete_list) != NULL)
2603 	{
2604 		p->delete_list=e->next;
2605 		free(e->userid);
2606 		free(e);
2607 	}
2608 }
2609 
2610 static void proxy_notify_email_msg(FILE *, struct proxy_list_entry *,
2611 				   const char *,
2612 				   const struct PCP_event_time *,
2613 				   unsigned);
2614 
proxy_notify_email(FILE * f,struct proxy_update_list * pul,const struct PCP_event_time * t,unsigned tn)2615 static void proxy_notify_email(FILE *f, struct proxy_update_list *pul,
2616 			       const struct PCP_event_time *t,
2617 			       unsigned tn)
2618 {
2619 	proxy_notify_email_msg(f, pul->new_list, "eventnotifynew.txt",
2620 			       t, tn);
2621 	proxy_notify_email_msg(f, pul->delete_list, "eventnotifydelete.txt",
2622 			       NULL, 0);
2623 }
2624 
2625 static void dosendnotice(FILE *, FILE *, FILE *, struct proxy_list_entry *,
2626 			 const char *, const struct PCP_event_time *,
2627 			 unsigned);
2628 
proxy_notify_email_msg(FILE * f,struct proxy_list_entry * l,const char * template,const struct PCP_event_time * t,unsigned tn)2629 static void proxy_notify_email_msg(FILE *f, struct proxy_list_entry *l,
2630 				   const char *template,
2631 				   const struct PCP_event_time *t,
2632 				   unsigned tn)
2633 {
2634 	FILE *tmpfp;
2635 	pid_t p, p2;
2636 	int waitstat;
2637 	int pipefd[2];
2638 	FILE *tofp;
2639 	const char *returnaddr=login_returnaddr();
2640 	char subjectlabel[100];
2641 
2642 	if (!l)
2643 		return;
2644 
2645 	if (fseek(f, 0L, SEEK_SET) < 0
2646 	    || lseek(fileno(f), 0L, SEEK_SET) < 0)
2647 	{
2648 		fprintf(stderr, "CRIT: seek failed: %s\n", strerror(errno));
2649 		return;
2650 	}
2651 
2652 	subjectlabel[0]=0;
2653 
2654 	if ((tmpfp=open_langform(sqwebmail_content_language,
2655 				 "eventnotifysubject.txt", 0)) != NULL)
2656 	{
2657 		if (fgets(subjectlabel, sizeof(subjectlabel), tmpfp) == NULL)
2658 			subjectlabel[0]=0;
2659 		else
2660 		{
2661 			char *p=strchr(subjectlabel, '\n');
2662 
2663 			if (p) *p=0;
2664 		}
2665 		fclose(tmpfp);
2666 	}
2667 	if (subjectlabel[0] == 0)
2668 		strcpy(subjectlabel, "[calendar]");
2669 
2670 	if ((tmpfp=open_langform(sqwebmail_content_language, template, 0))
2671 	    == NULL)
2672 	{
2673 		fprintf(stderr, "CRIT: %s: %s\n", template, strerror(errno));
2674 		return;
2675 	}
2676 
2677 	signal(SIGPIPE, SIG_IGN);
2678 
2679 	if (pipe(pipefd) < 0)
2680 	{
2681 		fclose(tmpfp);
2682 		fprintf(stderr, "CRIT: pipe: %s\n", strerror(errno));
2683 		return;
2684 	}
2685 
2686 	p=fork();
2687 
2688 	if (p < 0)
2689 	{
2690 		close(pipefd[0]);
2691 		close(pipefd[1]);
2692 		fclose(tmpfp);
2693 		fprintf(stderr, "CRIT: fork: %s\n", strerror(errno));
2694 		return;
2695 	}
2696 
2697 	if (p == 0)
2698 	{
2699 		dup2(pipefd[0], 0);
2700 		close(pipefd[0]);
2701 		close(pipefd[1]);
2702 		execl(SENDITSH, "sendit.sh", returnaddr,
2703                                 sqwebmail_mailboxid, NULL);
2704 		fprintf(stderr, "CRIT: exec " SENDITSH ": %s\n", strerror(errno));
2705 		exit(1);
2706 	}
2707 	close(pipefd[0]);
2708 	if ((tofp=fdopen(pipefd[1], "w")) == NULL)
2709 	{
2710 		fprintf(stderr, "CRIT: exec " SENDITSH ": %s\n", strerror(errno));
2711 	}
2712 	else
2713 	{
2714 		dosendnotice(tofp, tmpfp, f, l, subjectlabel, t, tn);
2715 	}
2716 	fclose(tofp);
2717 	close(pipefd[1]);
2718 	fclose(tmpfp);
2719 
2720 	waitstat=256;
2721 	while ((p2=wait(&waitstat)) != p && p2 >= 0)
2722 		;
2723 
2724 	if (!WIFEXITED(waitstat) || WEXITSTATUS(waitstat))
2725 		fprintf(stderr, "CRIT: event notify mail failed\n");
2726 }
2727 
2728 /*
2729 ** Ok, the preliminaries are out of the way, now spit it out.
2730 */
2731 
dosendnotice(FILE * tofp,FILE * tmpfp,FILE * eventfp,struct proxy_list_entry * idlist,const char * subjectlabel,const struct PCP_event_time * time_list,unsigned n_time_list)2732 static void dosendnotice(FILE *tofp,	/* Pipe to sendit.sh */
2733 			 FILE *tmpfp,	/*
2734 					** Template file with MIME headers and
2735 					** canned verbiage
2736 					*/
2737 			 FILE *eventfp,	/* Original event */
2738 			 struct proxy_list_entry *idlist,
2739 			 const char *subjectlabel,
2740 			 const struct PCP_event_time *time_list,
2741 			 unsigned n_time_list)
2742 {
2743 	struct rfc822hdr h;
2744 	const char *p;
2745 	int c;
2746 	unsigned u;
2747 
2748 	rfc822hdr_init(&h, 8192);
2749 
2750 	while (rfc822hdr_read(&h, eventfp, NULL, 0) == 0)
2751 	{
2752 		if (strcasecmp(h.header, "From") == 0 ||
2753 		    strcasecmp(h.header, "Date") == 0)
2754 		{
2755 			fprintf(tofp, "%s: %s\n", h.header,
2756 				h.value ? h.value:"");
2757 		}
2758 		else if (strcasecmp(h.header, "Subject") == 0)
2759 		{
2760 			fprintf(tofp, "%s: %s %s\n", h.header,
2761 				subjectlabel,
2762 				h.value ? h.value:"");
2763 		}
2764 	}
2765 	rfc822hdr_free(&h);
2766 
2767 	p="To: ";
2768 
2769 	while (idlist)
2770 	{
2771 		fprintf(tofp, "%s%s", p, idlist->userid);
2772 		p=",\n  ";
2773 		idlist=idlist->next;
2774 	}
2775 	fprintf(tofp, "\n");
2776 
2777 	while ((c=getc(tmpfp)) != EOF)
2778 		putc(c, tofp);
2779 
2780 	for (u=0; u<n_time_list; u++)
2781 	{
2782 		char buffer[200];
2783 
2784 		if (pcp_fmttimerange(buffer, sizeof(buffer),
2785 				     time_list[u].start,
2786 				     time_list[u].end) == 0)
2787 		{
2788 			fprintf(tofp, "     %s\n", buffer);
2789 		}
2790 	}
2791 }
2792 
dosave(FILE * fp,struct saveinfo * si)2793 static int dosave(FILE *fp, struct saveinfo *si)
2794 {
2795 	struct PCP *pcp=sqpcp_calendar();
2796 	struct PCP_save_event se;
2797 	struct PCP_new_eventid *nei;
2798 	struct PCP_commit c;
2799 
2800 	struct proxy_update_list pul;
2801 
2802 	if (!pcp)
2803 	{
2804 		cgi_put("error", "calendar");	/* TODO: actual error */
2805 		cgi_put("pcperror", "");
2806 		return (-1);
2807 	}
2808 
2809 	memset(&se, 0, sizeof(se));
2810 	se.write_event_fd=fileno(fp);
2811 	se.event_participants=si->participants;
2812 	se.n_event_participants=si->n_participants;
2813 
2814 	if (*cgi("okconflict"))
2815 		se.flags |= PCP_OK_CONFLICT;
2816 	if (*cgi("okerrors"))
2817 		se.flags |= PCP_OK_PROXY_ERRORS;
2818 
2819 	nei=pcp_new_eventid(pcp, si->old_eventid, &se);
2820 	if (!nei)
2821 	{
2822 		saveerror(pcp, NULL);
2823 		return (-1);
2824 	}
2825 
2826 	memset(&c, 0, sizeof(c));
2827 	c.event_times=si->times;
2828 	c.n_event_times=si->n_times;
2829 	c.flags=se.flags;
2830 
2831 	init_save_conflict();
2832 	c.add_conflict_callback=save_conflict;
2833 
2834 	memset(&pul, 0, sizeof(pul));
2835 
2836 	c.proxy_callback= &proxy_update_list_save;
2837 	c.proxy_callback_ptr= &pul;
2838 
2839 	if (pcp_commit(pcp, nei, &c))
2840 	{
2841 		proxy_update_list_free(&pul);
2842 		saveerror(pcp, &c.errcode);
2843 		pcp_destroy_eventid(pcp, nei);
2844 		return (-1);
2845 	}
2846 	pcp_destroy_eventid(pcp, nei);
2847 	unlink(CACHE);	/* Have it rebuilt */
2848 	proxy_notify_email(fp, &pul, c.event_times, c.n_event_times);
2849 	proxy_update_list_free(&pul);
2850 	refreshcache(pcp);
2851 	return (0);
2852 }
2853 
2854 /* -------------- Daily stuff --------------- */
2855 
sqpcp_todays_date()2856 void sqpcp_todays_date()
2857 {
2858 	unsigned y, m, d;
2859 	time_t start;
2860 	time_t end;
2861 	char buf[100];
2862 
2863 	if (sscanf(cgi("date"), "%4u%2u%2u", &y, &m, &d) != 3
2864 	    || pcp_parse_ymd(y, m, d, &start, &end)
2865 	    || pcp_fmttime(buf, sizeof(buf), start, FMTTIME_DATE))
2866 		return;
2867 
2868 	print_safe(buf);
2869 }
2870 
sqpcp_todays_date_verbose()2871 void sqpcp_todays_date_verbose()
2872 {
2873 	unsigned y, m, d;
2874 	time_t start;
2875 	time_t end;
2876 	char buf[500];
2877 	struct tm *tmptr;
2878 
2879 	if (sscanf(cgi("date"), "%4u%2u%2u", &y, &m, &d) != 3
2880 	    || pcp_parse_ymd(y, m, d, &start, &end)
2881 	    || (tmptr=localtime(&start)) == NULL
2882 	    || strftime(buf, sizeof(buf), getarg("DATEFORMAT"), tmptr) == 0)
2883 		return;
2884 
2885 	print_safe(buf);
2886 }
2887 
sqpcp_weeklylink()2888 void sqpcp_weeklylink()
2889 {
2890 	output_scriptptrget();
2891 	printf("&amp;form=eventweekly&amp;weekof=%s", cgi("date"));
2892 }
2893 
sqpcp_monthlylink()2894 void sqpcp_monthlylink()
2895 {
2896 	const char *p=cgi("date");
2897 
2898 	if (!*p)
2899 		p=cgi("weekof");
2900 	output_scriptptrget();
2901 	printf("&amp;form=eventmonthly&amp;monthof=%s", p);
2902 }
2903 
2904 #define VIEW_DAILY	0
2905 #define	VIEW_WEEKLY	1
2906 #define VIEW_MONTHLY	2
2907 
2908 static void do_daily_view(struct cacherecord *, unsigned, int,
2909 			  time_t *, time_t *);
2910 
show_pcp_errmsg(const char * p)2911 static void show_pcp_errmsg(const char *p)
2912 {
2913 	printf("<pre class=\"error\">");
2914 	output_attrencoded_oknl_fp(p, stdout);
2915 	printf("</pre>");
2916 }
2917 
sqpcp_daily_view()2918 void sqpcp_daily_view()
2919 {
2920 	unsigned y, m, d;
2921 	time_t start;
2922 	time_t end;
2923 
2924 	struct PCP *pcp;
2925 	struct cacherecord *recs;
2926 	unsigned n_recs;
2927 
2928 	if (*cgi("clearcache"))
2929 		unlink(CACHE);
2930 
2931 	if (sscanf(cgi("date"), "%4u%2u%2u", &y, &m, &d) != 3
2932 	    || pcp_parse_ymd(y, m, d, &start, &end))
2933 		return;
2934 
2935 	if ((pcp=sqpcp_calendar()) == NULL)
2936 	{
2937 		printf("<span class=\"error\">%s</span>", strerror(errno));
2938 		return;
2939 	}
2940 
2941 	if (createcache(pcp, &recs, &n_recs, start, end))
2942 	{
2943 		show_pcp_errmsg(pcp_errmsg(pcp));
2944 		return;
2945 	}
2946 
2947 	(void)do_daily_view(recs, n_recs, VIEW_DAILY, NULL, NULL);
2948 	destroycache(recs, n_recs);
2949 }
2950 
print_event_link_url(const char * id,const char * extra)2951 static void print_event_link_url(const char *id, const char *extra)
2952 {
2953 	output_scriptptrget();
2954 	printf("%s&amp;form=eventshow&amp;eventid=", extra);
2955 	output_urlencoded(id);
2956 	if (*cgi("date"))
2957 		printf("&amp;date=%s", cgi("date"));
2958 	if (*cgi("weekof"))
2959 		printf("&amp;weekof=%s", cgi("weekof"));
2960 	if (*cgi("monthof"))
2961 		printf("&amp;monthof=%s", cgi("monthof"));
2962 }
2963 
print_event_link(const char * id,const char * extra,const char * extra2)2964 static void print_event_link(const char *id, const char *extra,
2965 			     const char *extra2)
2966 {
2967 	printf("<a href=\"");
2968 	print_event_link_url(id, extra);
2969 	printf("\" %s >", extra2);
2970 }
2971 
do_daily_view(struct cacherecord * recs,unsigned n_recs,int viewtype,time_t * start_ptr,time_t * end_ptr)2972 static void do_daily_view(struct cacherecord *recs, unsigned n_recs,
2973 			  int viewtype, time_t *start_ptr, time_t *end_ptr)
2974 {
2975 	unsigned i;
2976 	int printed=0;
2977 
2978 	printf("<table width=\"100%%\">");
2979 
2980 	for (i=0; i<n_recs; i++)
2981 	{
2982 		char date1[256];
2983 		char date2[256];
2984 
2985 		char time1[128];
2986 		char time2[128];
2987 
2988 		time_t start=recs[i].start;
2989 		time_t end=recs[i].end;
2990 
2991 		if (start_ptr && *start_ptr >= end)
2992 			continue;
2993 
2994 		if (end_ptr && *end_ptr <= start)
2995 			continue;
2996 
2997 		if ( start_ptr && *start_ptr > start)
2998 			start= *start_ptr;
2999 
3000 		if ( end_ptr && *end_ptr < end)
3001 			end= *end_ptr;
3002 
3003 		if (pcp_fmttime(date1, sizeof(date1),
3004 				start, FMTTIME_DATE))
3005 			continue;
3006 		if (pcp_fmttime(date2, sizeof(date2),
3007 				end, FMTTIME_DATE))
3008 				continue;
3009 
3010 		printed=1;
3011 
3012 		if (strcmp(date1, date2) && viewtype == VIEW_DAILY)
3013 		{
3014 			char timerange[512];
3015 
3016 			if (pcp_fmttimerange(timerange, sizeof(timerange),
3017 					     start, end))
3018 				continue;
3019 
3020 			printf("<tr><td align=\"left\">");
3021 			print_event_link(recs[i].eventid, "", "class=\"dailyeventtimes\"");
3022 			print_safe(timerange);
3023 		}
3024 		else
3025 		{
3026 			if (pcp_fmttime(time1, sizeof(time1),
3027 					start,
3028 					FMTTIME_TIME))
3029 				continue;
3030 
3031 			if (pcp_fmttime(time2,
3032 					sizeof(time2),
3033 					end,
3034 					FMTTIME_TIME))
3035 				continue;
3036 
3037 			printf("<tr><td align=\"left\">");
3038 			print_event_link(recs[i].eventid, "", "class=\"dailyeventtimes\"");
3039 			print_safe(time1);
3040 			printf("&nbsp;-&nbsp;");
3041 			print_safe(time2);
3042 		}
3043 		printf("</a>");
3044 
3045 		if (viewtype == VIEW_DAILY)
3046 		{
3047 			printf("</td><td width=\"100%%\">");
3048 		}
3049 		else
3050 			printf("<br />");
3051 
3052 		printf("&nbsp;&nbsp;");
3053 		print_event_link(recs[i].eventid, "", "class=\"dailyeventsubject\"");
3054 		print_event_subject(recs[i].flags, recs[i].subject,
3055 				    viewtype == VIEW_DAILY ? 80:15);
3056 		printf("</a>");
3057 		if (viewtype != VIEW_DAILY)
3058 			printf("<br />&nbsp;");
3059 
3060 		printf("</td></tr>\n");
3061 	}
3062 
3063 	if (!printed)
3064 	{
3065 		printf("<tr><td align=\"center\">%s</td></tr>",
3066 		       getarg("NOEVENTS"));
3067 	}
3068 
3069 	printf("</table>\n");
3070 }
3071 
sqpcp_prevday()3072 void sqpcp_prevday()
3073 {
3074 	unsigned y, m, d;
3075 	time_t start;
3076 	time_t end;
3077 	struct tm *tm;
3078 	char buf[256];
3079 
3080 	if (sscanf(cgi("date"), "%4u%2u%2u", &y, &m, &d) != 3
3081 	    || pcp_parse_ymd(y, m, d, &start, &end))
3082 		return;
3083 
3084 	start -= 12 * 60 * 60;
3085 
3086 	if ((tm=localtime(&start)) == NULL)
3087 		return;
3088 
3089 	y=tm->tm_year + 1900;
3090 	m=tm->tm_mon + 1;
3091 	d=tm->tm_mday;
3092 
3093 	if (pcp_parse_ymd(y, m, d, &start, &end)
3094 	    || (tm=localtime(&start)) == NULL
3095 	    || strftime(buf, sizeof(buf), getarg("PREVDAY"), tm) == 0)
3096 		return;
3097 
3098 	printf("<a class=\"dailynextprev\" href=\"");
3099 	output_scriptptrget();
3100 	printf("&amp;form=eventdaily&amp;date=%04d%02d%02d\">%s</a>", y, m, d, buf);
3101 }
3102 
sqpcp_nextday()3103 void sqpcp_nextday()
3104 {
3105 	unsigned y, m, d;
3106 	time_t start;
3107 	time_t end;
3108 	struct tm *tm;
3109 	char buf[256];
3110 
3111 	if (sscanf(cgi("date"), "%4u%2u%2u", &y, &m, &d) != 3
3112 	    || pcp_parse_ymd(y, m, d, &start, &end))
3113 		return;
3114 
3115 	start=end;
3116 
3117 	if ((tm=localtime(&start)) == NULL)
3118 		return;
3119 
3120 	y=tm->tm_year + 1900;
3121 	m=tm->tm_mon + 1;
3122 	d=tm->tm_mday;
3123 
3124 	if (pcp_parse_ymd(y, m, d, &start, &end)
3125 	    || (tm=localtime(&start)) == NULL
3126 	    || strftime(buf, sizeof(buf), getarg("NEXTDAY"), tm) == 0)
3127 		return;
3128 
3129 	printf("<a class=\"dailynextprev\" href=\"");
3130 	output_scriptptrget();
3131 	printf("&amp;form=eventdaily&amp;date=%04d%02d%02d\">%s</a>", y, m, d, buf);
3132 }
3133 
3134 /* -------------- Display event stuff --------------- */
3135 
3136 struct display_retr_time_list {
3137 	struct display_retr_time_list *next;
3138 	time_t start;
3139 	time_t end;
3140 } ;
3141 
3142 struct display_retr_participant_list {
3143 	struct display_retr_participant_list *next;
3144 	char *participant;
3145 } ;
3146 
3147 struct display_retr {
3148 	FILE *f;
3149 
3150 	struct display_retr_time_list *time_list;
3151 	struct display_retr_participant_list *participant_list;
3152 
3153 } ;
3154 
free_display_retr(struct display_retr * r)3155 static void free_display_retr(struct display_retr *r)
3156 {
3157 }
3158 
3159 
3160 static int save_displayed_event(struct PCP_retr *, const char *, int, void *);
3161 
3162 static int set_status(struct PCP_retr *, int, void *);
3163 
sqpcp_displayeventinit()3164 void sqpcp_displayeventinit()
3165 {
3166 	struct PCP *pcp;
3167 	const char *event_id_list[2];
3168 	struct PCP_retr r;
3169 
3170 	showerror();
3171 
3172 	pcp=sqpcp_calendar();
3173 
3174 	if (!pcp)
3175 		return;
3176 
3177 	event_id_list[0]=cgi("eventid");
3178 	event_id_list[1]=0;
3179 
3180 	init_save_conflict();
3181 	if (*cgi("docancel"))
3182 	{
3183 		if (pcp_cancel(pcp, event_id_list[0], NULL))
3184 			show_pcp_errmsg(pcp_errmsg(pcp));
3185 		unlink(CACHE);
3186 	}
3187 
3188 	if (*cgi("douncancel"))
3189 	{
3190 		struct PCP_uncancel u;
3191 		int flags=0;
3192 
3193 		memset(&u, 0, sizeof(u));
3194 
3195 		if (*cgi("okconflict"))
3196 			flags |= PCP_OK_CONFLICT;
3197 
3198 		u.uncancel_conflict_callback=save_conflict;
3199 		if (pcp_uncancel(pcp, event_id_list[0], flags, &u))
3200 		{
3201 			saveerror(pcp, &u.errcode);
3202 			showerror();
3203 			if (u.errcode == PCP_ERR_CONFLICT)
3204 				cgi_put("okconflict", "1");
3205 		}
3206 		unlink(CACHE);
3207 	}
3208 
3209 	memset(&r, 0, sizeof(r));
3210 	r.event_id_list=event_id_list;
3211 	r.callback_retr_status=set_status;
3212 
3213 	if (pcp_retr(pcp, &r))
3214 	{
3215 		show_pcp_errmsg(pcp_errmsg(pcp));
3216 		return;
3217 	}
3218 
3219 }
3220 
set_status(struct PCP_retr * pcp,int status,void * dummy)3221 static int set_status(struct PCP_retr *pcp, int status, void *dummy)
3222 {
3223 	cgi_put("event_cancelled", status & LIST_CANCELLED ? "1":"");
3224 	cgi_put("event_booked", status & LIST_BOOKED ? "1":"");
3225 	cgi_put("event_proxy", status & LIST_PROXY ? "1":"");
3226 	return (0);
3227 }
3228 
save_displayed_date(struct PCP_retr * r,time_t start,time_t end,void * vp)3229 static int save_displayed_date(struct PCP_retr *r, time_t start, time_t end,
3230 			       void *vp)
3231 {
3232 	struct display_retr *dr=(struct display_retr *)vp;
3233 
3234 	struct display_retr_time_list **ptr, *p;
3235 
3236 	for (ptr= &dr->time_list; *ptr; ptr=&(*ptr)->next)
3237 		if ((*ptr)->start > start)
3238 			break;
3239 
3240 	if ((p=malloc(sizeof(struct display_retr_time_list))) == NULL)
3241 		return (-1);
3242 
3243 	p->next= *ptr;
3244 	*ptr=p;
3245 	p->start=start;
3246 	p->end=end;
3247 
3248 	return (0);
3249 }
3250 
save_displayed_participants(struct PCP_retr * r,const char * address,const char * dummy,void * vp)3251 static int save_displayed_participants(struct PCP_retr *r, const char *address,
3252 				       const char *dummy, void *vp)
3253 {
3254 	struct display_retr *dr=(struct display_retr *)vp;
3255 
3256 	struct display_retr_participant_list **ptr, *p;
3257 
3258 	for (ptr= &dr->participant_list; *ptr; ptr=&(*ptr)->next)
3259 		if (strcasecmp((*ptr)->participant, address) > 0)
3260 			break;
3261 
3262 	if ((p=malloc(sizeof(struct display_retr_participant_list))) == NULL)
3263 		return (-1);
3264 
3265 	if ((p->participant=strdup(address)) == NULL)
3266 	{
3267 		free(p);
3268 		return (-1);
3269 	}
3270 	p->next= *ptr;
3271 	*ptr=p;
3272 	return (0);
3273 }
3274 
sqpcp_displayevent()3275 void sqpcp_displayevent()
3276 {
3277 	struct PCP *pcp=sqpcp_calendar();
3278 	const char *event_id_list[2];
3279 	struct PCP_retr r;
3280 	struct display_retr dr;
3281 	struct maildir_tmpcreate_info createInfo;
3282 	struct display_retr_time_list *tl;
3283 	struct display_retr_participant_list *pl;
3284 
3285 	if (!pcp)
3286 		return;
3287 
3288 	event_id_list[0]=cgi("eventid");
3289 	event_id_list[1]=0;
3290 
3291 	memset(&r, 0, sizeof(r));
3292 	memset(&dr, 0, sizeof(dr));
3293 	r.event_id_list=event_id_list;
3294 	r.callback_arg=&dr;
3295 	r.callback_rfc822_func=save_displayed_event;
3296 	r.callback_retr_date=save_displayed_date;
3297 	r.callback_retr_participants=save_displayed_participants;
3298 
3299 	maildir_purgemimegpg(); /* Delete previous :calendar: file */
3300 
3301 	maildir_tmpcreate_init(&createInfo);
3302 	createInfo.uniq=":calendar:";
3303 	createInfo.doordie=1;
3304 
3305 	if ((dr.f=maildir_tmpcreate_fp(&createInfo)) == NULL)
3306 	{
3307 		error(strerror(errno));
3308 	}
3309 
3310 	cgi_put(MIMEGPGFILENAME, strrchr(createInfo.tmpname, '/')+1);
3311 
3312 	if (pcp_retr(pcp, &r))
3313 	{
3314 		free_display_retr(&dr);
3315 		fclose(dr.f);
3316 		cgi_put(MIMEGPGFILENAME, "");
3317 		unlink(createInfo.tmpname);
3318 		maildir_tmpcreate_free(&createInfo);
3319 		show_pcp_errmsg(pcp_errmsg(pcp));
3320 		return;
3321 	}
3322 	fclose(dr.f);
3323 
3324 	printf("<table class=\"calendarevent\" align=\"center\" border=\"0\"><tr valign=\"top\"><th align=\"left\">%s</th><td>",
3325 	       getarg("EVENT"));
3326 
3327 	for (tl=dr.time_list; tl; tl=tl->next)
3328 	{
3329 		char buffer[512];
3330 
3331 		if (pcp_fmttimerange(buffer, sizeof(buffer),
3332 				     tl->start, tl->end))
3333 			continue;
3334 
3335 		printf("<span class=\"tt\">");
3336 		print_safe(buffer);
3337 		printf("</span><br />\n");
3338 	}
3339 	printf("</td></tr>\n");
3340 
3341 	if (dr.participant_list)
3342 	{
3343 		printf("<tr valign=\"top\"><th align=\"left\">%s</th><td>",
3344 		       getarg("PARTICIPANTS"));
3345 		for (pl=dr.participant_list; pl; pl=pl->next)
3346 		{
3347 			printf("<span class=\"tt\">&lt;");
3348 			print_safe(pl->participant);
3349 			printf("&gt;</span><br />\n");
3350 		}
3351 		printf("</td></tr>");
3352 	}
3353 	printf("</table>\n");
3354 	folder_showmsg(INBOX "." DRAFTS, 0);
3355 	free_display_retr(&dr);
3356 	cgi_put(MIMEGPGFILENAME, "");
3357 	maildir_tmpcreate_free(&createInfo);
3358 }
3359 
save_displayed_event(struct PCP_retr * r,const char * buf,int cnt,void * vp)3360 static int save_displayed_event(struct PCP_retr *r,
3361 				const char *buf, int cnt,
3362 				void *vp)
3363 {
3364 	if (fwrite( buf, cnt, 1, ((struct display_retr *)vp)->f) != 1)
3365 		return (-1);
3366 
3367 	return (0);
3368 }
3369 
3370 
back_to_summary()3371 static void back_to_summary()
3372 {
3373 	const char *p;
3374 
3375 	if (*(p=cgi("monthof")) != 0)
3376 	{
3377 		printf("&amp;form=eventmonthly&amp;monthof=%s", p);
3378 	}
3379 	else if (*(p=cgi("weekof")) != 0)
3380 	{
3381 		printf("&amp;form=eventweekly&amp;weekof=%s", p);
3382 	}
3383 	else
3384 	{
3385 		p=cgi("date");
3386 		printf("&amp;form=eventdaily&amp;date=%s", p);
3387 	}
3388 }
3389 
sqpcp_eventbacklink()3390 void sqpcp_eventbacklink()
3391 {
3392 	output_scriptptrget();
3393 	back_to_summary();
3394 }
3395 
sqpcp_eventeditlink()3396 void sqpcp_eventeditlink()
3397 {
3398 	const char *p=cgi("date");
3399 
3400 	output_scriptptrget();
3401 	printf("&amp;form=event-edit&amp;date=%s&amp;eventid=", p);
3402 	output_urlencoded(cgi("eventid"));
3403 }
3404 
sqpcp_eventdeletelink()3405 void sqpcp_eventdeletelink()
3406 {
3407 	const char *p=cgi("date");
3408 
3409 	output_scriptptrget();
3410 	printf("&amp;eventid=");
3411 
3412 	output_urlencoded(cgi("eventid"));
3413 	printf("&amp;form=eventdelete&amp;date=%s", p);
3414 }
3415 
sqpcp_eventcanceluncancellink()3416 void sqpcp_eventcanceluncancellink()
3417 {
3418 	print_event_link_url(cgi("eventid"), *cgi("event_cancelled")
3419 			 ? (*cgi("okconflict") ?
3420 			    "&amp;okconflict=1&amp;douncancel=1"
3421 			    :"&amp;douncancel=1")
3422 			     :"&amp;docancel=1");
3423 }
3424 
sqpcp_eventcanceluncancelimage()3425 void sqpcp_eventcanceluncancelimage()
3426 {
3427 	printf("%s", getarg(*cgi("event_cancelled")
3428 			    ? "UNCANCELIMAGE":"CANCELIMAGE"));
3429 }
3430 
sqpcp_eventcanceluncanceltext()3431 void sqpcp_eventcanceluncanceltext()
3432 {
3433 	printf("%s", getarg(*cgi("event_cancelled")
3434 			    ? "UNCANCELTEXT":"CANCELTEXT"));
3435 }
3436 
sqpcp_deleteeventinit()3437 void sqpcp_deleteeventinit()
3438 {
3439 	sqpcp_displayeventinit();
3440 	if (*cgi("event_proxy"))
3441 		printf("%s", getarg("PROXYWARN"));
3442 }
3443 
save_orig_headers(struct PCP_retr * pcp,const char * h,const char * v,void * vp)3444 static int save_orig_headers(struct PCP_retr *pcp,
3445 			     const char *h, const char *v, void *vp)
3446 {
3447 	FILE *fp=(FILE *)vp;
3448 
3449 	if (strcasecmp(h, "Date"))
3450 		fprintf(fp, "%s: %s\n", h, v);
3451 	return (0);
3452 }
3453 
3454 
sqpcp_dodelete()3455 void sqpcp_dodelete()
3456 {
3457 	struct PCP *pcp=sqpcp_calendar();
3458 	struct PCP_retr r;
3459 	const char *event_list_ary[2];
3460 	struct PCP_delete del;
3461 	struct proxy_update_list pul;
3462 	FILE *tmpfp;
3463 
3464 	if (!pcp)
3465 		return;
3466 
3467 	memset(&del, 0, sizeof(del));
3468 	del.id=cgi("eventid");
3469 
3470 	memset(&r, 0, sizeof(r));
3471 	event_list_ary[0]=del.id;
3472 	event_list_ary[1]=NULL;
3473 	r.event_id_list=event_list_ary;
3474 	r.callback_headers_func=save_orig_headers;
3475 
3476 	tmpfp=tmpfile();
3477 	if (!tmpfp)
3478 		enomem();
3479 	r.callback_arg=tmpfp;
3480 	pcp_retr(pcp, &r);
3481 
3482 	{
3483 		time_t t;
3484 
3485 		time(&t);
3486 
3487 		fprintf(tmpfp, "Date: %s\n\n", rfc822_mkdate(t));
3488 	}
3489 
3490 	memset(&pul, 0, sizeof(pul));
3491 	del.proxy_callback=&proxy_update_list_save;
3492 	del.proxy_callback_ptr=&pul;
3493 
3494 	if (pcp_delete(pcp, &del))
3495 	{
3496 		saveerror(pcp, &del.errcode);
3497 		output_form("eventdelete.html");
3498 	}
3499 	else
3500 	{
3501 		proxy_notify_email(tmpfp, &pul, NULL, 0);
3502 	}
3503 	fclose(tmpfp);
3504 	proxy_update_list_free(&pul);
3505 	unlink(CACHE);
3506 	output_form("eventdaily.html");
3507 }
3508 
3509 /* ------------- Bring in an event to edit -------------------------- */
3510 
3511 static int doeventedit(struct PCP *, int);
3512 
sqpcp_eventedit()3513 int sqpcp_eventedit()
3514 {
3515 	struct PCP *pcp=sqpcp_calendar();
3516 	int newdraftfd;
3517 	char *draftfilename;
3518 
3519 	if (!pcp)
3520 		return (-1);
3521 
3522 	newdraftfd=maildir_createmsg(INBOX "." DRAFTS, 0, &draftfilename);
3523 	if (doeventedit(pcp, newdraftfd))
3524 	{
3525 		maildir_deletenewmsg(newdraftfd, INBOX "." DRAFTS, draftfilename);
3526 	}
3527 	else if (maildir_closemsg(newdraftfd, INBOX "." DRAFTS, draftfilename, 1, 0))
3528 	{
3529 		cgi_put("error", "quota");
3530 	}
3531 	else
3532 	{
3533 		static char *filenamebuf=0;
3534 
3535 		if (filenamebuf)
3536 			free(filenamebuf);
3537 
3538 		filenamebuf=draftfilename;
3539 		cgi_put("draftmessage", filenamebuf);
3540 		return (0);
3541 	}
3542 	free(draftfilename);
3543 	return (-1);
3544 }
3545 
3546 struct getedit_info {
3547 	int fd;
3548 	int flag;
3549 
3550 	int in_headers;
3551 	int sol;
3552 	int skiph;
3553 
3554 } ;
3555 
get_date(struct PCP_retr * r,time_t start,time_t end,void * vp)3556 static int get_date(struct PCP_retr *r, time_t start, time_t end, void *vp)
3557 {
3558 	char buf[NUMBUFSIZE];
3559 	struct getedit_info *ge=(struct getedit_info *)vp;
3560 
3561 	maildir_writemsgstr(ge->fd, "X-Event-Time: ");
3562 	maildir_writemsgstr(ge->fd, libmail_str_time_t(start, buf));
3563 	maildir_writemsgstr(ge->fd, " ");
3564 	maildir_writemsgstr(ge->fd, libmail_str_time_t(end, buf));
3565 	maildir_writemsgstr(ge->fd, "\n");
3566 
3567 	return (0);
3568 }
3569 
get_participants(struct PCP_retr * r,const char * address,const char * dummy,void * vp)3570 static int get_participants(struct PCP_retr *r, const char *address,
3571 			    const char *dummy, void *vp)
3572 {
3573 	struct getedit_info *ge=(struct getedit_info *)vp;
3574 
3575 	maildir_writemsgstr(ge->fd, "X-Event-Participant: ");
3576 	maildir_writemsgstr(ge->fd, address);
3577 	maildir_writemsgstr(ge->fd, "\n");
3578 
3579 	return (0);
3580 }
3581 
get_msgtext(struct PCP_retr * r,const char * ptr,int n,void * vp)3582 static int get_msgtext(struct PCP_retr *r, const char *ptr, int n, void *vp)
3583 {
3584 	struct getedit_info *ge=(struct getedit_info *)vp;
3585 
3586 	/* We want to drop all X headers when we read in this event */
3587 	/* Also, drop CRs */
3588 
3589 	ge->flag=1;
3590 
3591 	while (n)
3592 	{
3593 		int i;
3594 
3595 		if (!ge->in_headers)	/* Write out msg body */
3596 		{
3597 			while (n)
3598 			{
3599 				if (*ptr == '\r')
3600 				{
3601 					++ptr;
3602 					--n;
3603 					continue;
3604 				}
3605 
3606 				for (i=0; i<n; i++)
3607 					if (ptr[i] == '\r')
3608 						break;
3609 
3610 				maildir_writemsg(ge->fd, ptr, i);
3611 				ptr += i;
3612 				n -= i;
3613 			}
3614 			break;
3615 		}
3616 
3617 		if (*ptr == '\r')
3618 		{
3619 			++ptr;
3620 			--n;
3621 			continue;
3622 		}
3623 
3624 		if (*ptr == '\n')
3625 		{
3626 			if (!ge->skiph)
3627 				maildir_writemsgstr(ge->fd, "\n");
3628 
3629 			ge->skiph=0;
3630 			if (ge->sol)
3631 				ge->in_headers=0;	/* End of headers */
3632 			ge->sol=1;
3633 			++ptr;
3634 			--n;
3635 			continue;
3636 		}
3637 
3638 		if (ge->sol && (*ptr == 'x' || *ptr == 'X'))
3639 			ge->skiph=1;
3640 
3641 		for (i=0; i<n; i++)
3642 			if (ptr[i] == '\r' || ptr[i] == '\n')
3643 				break;
3644 
3645 		if (!ge->skiph)	/* Skip X- header */
3646 			maildir_writemsg(ge->fd, ptr, i);
3647 		ptr += i;
3648 		n -= i;
3649 	}
3650 	return (0);
3651 }
3652 
doeventedit(struct PCP * pcp,int fd)3653 static int doeventedit(struct PCP *pcp, int fd)
3654 {
3655 	const char *p=cgi("eventid");
3656 	struct PCP_retr r;
3657 	struct getedit_info ge;
3658 
3659 	const char *eventid[2];
3660 
3661 	if (!p || !*p)
3662 		return (-1);
3663 
3664 	maildir_writemsgstr(fd, "X-Event: 1\nX-Old-EventId: ");
3665 	maildir_writemsgstr(fd, p);
3666 	maildir_writemsgstr(fd, "\n");
3667 
3668 	memset(&r, 0, sizeof(r));
3669 	eventid[0]=p;
3670 	eventid[1]=NULL;
3671 
3672 	r.event_id_list=eventid;
3673 
3674 	ge.fd=fd;
3675 	ge.flag=0;
3676 	r.callback_arg=&ge;
3677 
3678 	r.callback_retr_date=get_date;
3679 	r.callback_retr_participants=get_participants;
3680 
3681 	if (pcp_retr(pcp, &r))
3682 	{
3683 		saveerror(pcp, &r.errcode);
3684 		return (-1);
3685 	}
3686 
3687 	memset(&r, 0, sizeof(r));
3688 	eventid[0]=p;
3689 	eventid[1]=NULL;
3690 
3691 	r.event_id_list=eventid;
3692 
3693 	ge.fd=fd;
3694 	ge.flag=0;
3695 	r.callback_arg=&ge;
3696 
3697 	ge.in_headers=1;
3698 	ge.sol=1;
3699 	ge.skiph=0;
3700 
3701 	r.callback_rfc822_func=get_msgtext;
3702 	if (pcp_retr(pcp, &r))
3703 	{
3704 		saveerror(pcp, &r.errcode);
3705 		return (-1);
3706 	}
3707 
3708 	if (!ge.flag)
3709 	{
3710 		cgi_put("error", "notfound");
3711 		return (-1);
3712 	}
3713 
3714 	return (0);
3715 }
3716 
3717 /* ------ Weekly stuff ------- */
3718 
prevday(time_t * tm)3719 static void prevday(time_t *tm)
3720 {
3721 	struct tm *tmptr;
3722 	time_t t= *tm - 12 * 60 * 60;
3723 
3724 	if ((tmptr=localtime(&t)) == NULL)
3725 	{
3726 		enomem();
3727 		return;
3728 	}
3729 
3730 	if (pcp_parse_ymd(tmptr->tm_year + 1900, tmptr->tm_mon + 1,
3731 			  tmptr->tm_mday, tm, &t))
3732 	{
3733 		enomem();
3734 	}
3735 }
3736 
nextday(time_t * tm)3737 static void nextday(time_t *tm)
3738 {
3739 	struct tm *tmptr;
3740 	time_t t= *tm + 36 * 60 * 60;
3741 
3742 	if ((tmptr=localtime(&t)) == NULL)
3743 	{
3744 		enomem();
3745 		return;
3746 	}
3747 
3748 	if (pcp_parse_ymd(tmptr->tm_year + 1900, tmptr->tm_mon + 1,
3749 			  tmptr->tm_mday, tm, &t))
3750 	{
3751 		enomem();
3752 	}
3753 }
3754 
get_start_of_week()3755 static time_t get_start_of_week()
3756 {
3757 	unsigned y, m, d;
3758 	time_t start;
3759 	time_t end;
3760 	struct tm *tmptr;
3761 	int i;
3762 
3763 	if (sscanf(cgi("weekof"), "%4u%2u%2u", &y, &m, &d) != 3
3764 	    || pcp_parse_ymd(y, m, d, &start, &end))
3765 	{
3766 		time(&start);
3767 		if ((tmptr=localtime(&start)) == NULL)
3768 		{
3769 			enomem();
3770 			return (0);
3771 		}
3772 		y=tmptr->tm_year + 1900;
3773 		m=tmptr->tm_mon + 1;
3774 		d=tmptr->tm_mday;
3775 
3776 		if (pcp_parse_ymd(y, m, d, &start, &end))
3777 		{
3778 			enomem();
3779 			return (0);
3780 		}
3781 	}
3782 
3783 	for (i=0; i<7; i++)
3784 	{
3785 		tmptr=localtime(&start);
3786 		if (!tmptr)
3787 			enomem();
3788 
3789 		if (tmptr->tm_wday == pref_startofweek)
3790 			break;
3791 
3792 		prevday(&start);
3793 	}
3794 
3795 	return (start);
3796 }
3797 
sqpcp_show_cal_week()3798 void sqpcp_show_cal_week()
3799 {
3800 	time_t start=get_start_of_week();
3801 	struct tm *tmptr;
3802 	char buf[512];
3803 
3804 	if ((tmptr=localtime(&start)) == NULL)
3805 		return;
3806 
3807 	if (strftime(buf, sizeof(buf), getarg("DATEFORMAT"), tmptr) == 0)
3808 		return;
3809 
3810 	print_safe(buf);
3811 }
3812 
sqpcp_show_cal_nextweek()3813 void sqpcp_show_cal_nextweek()
3814 {
3815 	time_t start=get_start_of_week();
3816 	int i;
3817 	struct tm *tmptr;
3818 
3819 	for (i=0; i<7; i++)
3820 		nextday(&start);
3821 
3822 	if ((tmptr=localtime(&start)) == NULL)
3823 		return;
3824 
3825 	output_scriptptrget();
3826 	printf("&amp;form=eventweekly&amp;weekof=%04d%02d%02d",
3827 	       tmptr->tm_year + 1900, tmptr->tm_mon+1, tmptr->tm_mday);
3828 
3829 }
3830 
sqpcp_show_cal_prevweek()3831 void sqpcp_show_cal_prevweek()
3832 {
3833 	time_t start=get_start_of_week();
3834 	int i;
3835 	struct tm *tmptr;
3836 
3837 	for (i=0; i<7; i++)
3838 		prevday(&start);
3839 
3840 	if ((tmptr=localtime(&start)) == NULL)
3841 		return;
3842 
3843 	output_scriptptrget();
3844 	printf("&amp;form=eventweekly&amp;weekof=%04d%02d%02d",
3845 	       tmptr->tm_year + 1900, tmptr->tm_mon+1, tmptr->tm_mday);
3846 
3847 }
3848 
sqpcp_displayweek()3849 void sqpcp_displayweek()
3850 {
3851 	int i;
3852 	time_t start=get_start_of_week(), save_start;
3853 	time_t end;
3854 	struct PCP *pcp=sqpcp_calendar();
3855 	struct cacherecord *recs;
3856 	unsigned n_recs;
3857 
3858 	if (!pcp)
3859 		return;
3860 
3861 	save_start=start;
3862 
3863 	for (i=0; i<7; i++)
3864 	{
3865 		nextday(&start);
3866 	}
3867 
3868 	if (createcache(pcp, &recs, &n_recs, save_start, start))
3869 	{
3870 		show_pcp_errmsg(pcp_errmsg(pcp));
3871 		return;
3872 	}
3873 
3874 	printf("<table align=\"center\" border=\"0\" class=\"weekly-border\""
3875 	       " cellpadding=\"0\" cellspacing=\"0\" width=\"100%%\">"
3876 	       "<tr><td>\n");
3877 	printf("<table border=\"1\" class=\"weekly-bg\" cellspacing=\"0\" cellpadding=\"10\" width=\"100%%\">"
3878 	       "<tr valign=\"top\">");
3879 
3880 	start=save_start;
3881 	for (i=0; i<7; i++)
3882 	{
3883 		const char *p;
3884 		struct tm *tmptr;
3885 
3886 		printf("<td width=\"14%%\">");
3887 		p=pcp_wdayname((i + pref_startofweek) % 7);
3888 		printf("<div align=\"center\" class=\"weekly-day\">");
3889 		printf("<a href=\"");
3890 		output_scriptptrget();
3891 		printf("&amp;form=eventdaily&amp;date=");
3892 
3893 		tmptr=localtime(&start);
3894 
3895 		if (tmptr)
3896 		{
3897 			printf("%04d%02d%02d", tmptr->tm_year + 1900,
3898 			       tmptr->tm_mon+1,
3899 			       tmptr->tm_mday);
3900 		}
3901 		printf("\">");
3902 		print_safe(p);
3903 		printf("</a><hr width=\"70%%\" />");
3904 		printf("</div>\n");
3905 
3906 		end=start;
3907 		nextday(&end);
3908 
3909 
3910 		do_daily_view(recs, n_recs, VIEW_WEEKLY, &start, &end);
3911 
3912 		start=end;
3913 		printf("</td>");
3914 	}
3915 	destroycache(recs, n_recs);
3916 	printf("</tr></table>\n");
3917 	printf("</td></tr></table>\n");
3918 }
3919 
3920 /* ---------------- Monthly view ---------------- */
3921 
get_start_of_month()3922 static time_t get_start_of_month()
3923 {
3924 	unsigned y, m;
3925 	time_t start;
3926 	time_t end;
3927 	struct tm *tmptr;
3928 
3929 	if (sscanf(cgi("monthof"), "%4u%2u", &y, &m) != 2
3930 	    || pcp_parse_ymd(y, m, 1, &start, &end))
3931 	{
3932 		time(&start);
3933 		if ((tmptr=localtime(&start)) == NULL)
3934 		{
3935 			enomem();
3936 			return (0);
3937 		}
3938 		y=tmptr->tm_year + 1900;
3939 		m=tmptr->tm_mon + 1;
3940 
3941 		if (pcp_parse_ymd(y, m, 1, &start, &end))
3942 		{
3943 			enomem();
3944 			return (0);
3945 		}
3946 	}
3947 
3948 	return (start);
3949 }
3950 
sqpcp_show_cal_month()3951 void sqpcp_show_cal_month()
3952 {
3953 	time_t start=get_start_of_month();
3954 	struct tm *tmptr;
3955 	char buf[512];
3956 
3957 	if ((tmptr=localtime(&start)) == NULL)
3958 		return;
3959 
3960 	if (strftime(buf, sizeof(buf), getarg("DATEFORMAT"), tmptr) == 0)
3961 		return;
3962 
3963 	print_safe(buf);
3964 
3965 }
3966 
sqpcp_show_cal_nextmonth()3967 void sqpcp_show_cal_nextmonth()
3968 {
3969 	time_t start=get_start_of_month();
3970 	struct tm *tmptr;
3971 	int m, y;
3972 
3973 	if ((tmptr=localtime(&start)) == NULL)
3974 		return;
3975 
3976 	y=tmptr->tm_year + 1900;
3977 	m=tmptr->tm_mon + 1;
3978 
3979 	++m;
3980 	if (m > 12)
3981 	{
3982 		m=1;
3983 		++y;
3984 	}
3985 
3986 	output_scriptptrget();
3987 	printf("&amp;form=eventmonthly&amp;monthof=%04d%02d01", y, m);
3988 }
3989 
sqpcp_show_cal_prevmonth()3990 void sqpcp_show_cal_prevmonth()
3991 {
3992 	time_t start=get_start_of_month();
3993 	struct tm *tmptr;
3994 	int m, y;
3995 
3996 	if ((tmptr=localtime(&start)) == NULL)
3997 		return;
3998 
3999 	y=tmptr->tm_year + 1900;
4000 	m=tmptr->tm_mon + 1;
4001 
4002 	--m;
4003 	if (m <= 0)
4004 	{
4005 		m=12;
4006 		--y;
4007 	}
4008 
4009 	output_scriptptrget();
4010 	printf("&amp;form=eventmonthly&amp;monthof=%04d%02d01", y, m);
4011 }
4012 
sqpcp_displaymonth()4013 void sqpcp_displaymonth()
4014 {
4015 	int i, y, m;
4016 	time_t start=get_start_of_month(), save_start;
4017 	time_t end;
4018 	struct PCP *pcp=sqpcp_calendar();
4019 	struct cacherecord *recs;
4020 	unsigned n_recs;
4021 	struct tm *tmptr;
4022 
4023 	if (!pcp)
4024 		return;
4025 
4026 	if ((tmptr=localtime(&start)) == NULL)
4027 		return;
4028 
4029 	y=tmptr->tm_year + 1900;
4030 	m=tmptr->tm_mon + 1;
4031 
4032 	if (++m > 12)
4033 	{
4034 		m=1;
4035 		++y;
4036 	}
4037 
4038 	if (pcp_parse_ymd(y, m, 1, &end, &save_start))
4039 		return;
4040 
4041 	if (createcache(pcp, &recs, &n_recs, start, end))
4042 	{
4043 		show_pcp_errmsg(pcp_errmsg(pcp));
4044 		return;
4045 	}
4046 
4047 	printf("<table align=\"center\" border=\"0\" class=\"monthly-border\""
4048 	       " cellpadding=\"0\" cellspacing=\"0\" width=\"100%%\">"
4049 	       "<tr><td>\n");
4050 	printf("<table border=\"1\" class=\"monthly-bg\" cellspacing=\"0\" cellpadding=\"10\" width=\"100%%\">"
4051 	       "<tr valign=\"top\">");
4052 
4053 	for (i=0; i<7; i++)
4054 	{
4055 		printf("<td width=\"14%%\" align=\"center\" class=\"monthly-day\">");
4056 		print_safe(pcp_wdayname((i + pref_startofweek) % 7));
4057 		printf("</td>");
4058 	}
4059 	printf("</tr>\n");
4060 
4061 	while (start < end)
4062 	{
4063 		printf("<tr valign=\"top\">\n");
4064 
4065 		for (i=0; i<7; i++)
4066 		{
4067 			struct tm *tmptr;
4068 			time_t next_day;
4069 
4070 			tmptr=localtime(&start);
4071 
4072 			if (tmptr->tm_wday != (i + pref_startofweek) % 7
4073 			    || start >= end)
4074 			{
4075 				printf("<td width=\"14%%\" class=\"monthly-bg-othermonth\">&nbsp;</td>");
4076 				continue;
4077 			}
4078 
4079 			printf("<td width=\"14%%\">");
4080 
4081 
4082 			printf("<a href=\"");
4083 			output_scriptptrget();
4084 			printf("&amp;form=eventdaily&amp;date=");
4085 
4086 			if (tmptr)
4087 			{
4088 				printf("%04d%02d%02d", tmptr->tm_year + 1900,
4089 				       tmptr->tm_mon+1,
4090 				       tmptr->tm_mday);
4091 			}
4092 			printf("\" class=\"monthly-day\">");
4093 
4094 			printf("%2d", tmptr->tm_mday);
4095 			printf("</a><div align=\"center\"><hr width=\"70%%\" /></div>\n");
4096 
4097 			next_day=start;
4098 			nextday(&next_day);
4099 
4100 			do_daily_view(recs, n_recs, VIEW_MONTHLY, &start,
4101 				      &next_day);
4102 
4103 			start=next_day;
4104 			printf("</td>\n");
4105 		}
4106 		printf("</tr>\n");
4107 	}
4108 	destroycache(recs, n_recs);
4109 	printf("</table>\n");
4110 	printf("</td></tr></table>\n");
4111 }
4112 
4113 /* -------------------------------------------------------------------- */
4114 /* Access control lists */
4115 
4116 static void addacl(const char *);
4117 
4118 struct acl_list {
4119 	struct acl_list *next;
4120 	char *addr;
4121 	char *name;
4122 	int flags;
4123 } ;
4124 
listacl(const char * a,int f,void * vp)4125 static int listacl(const char *a, int f, void *vp)
4126 {
4127 	struct acl_list **p=(struct acl_list **)vp, *q;
4128 
4129 	if ((q=malloc(sizeof(struct acl_list))) == NULL)
4130 		return (-1);
4131 	memset(q, 0, sizeof(*q));
4132 	if ((q->addr=strdup(a)) == NULL)
4133 	{
4134 		free(q);
4135 		return (-1);
4136 	}
4137 
4138 	q->flags=f;
4139 
4140 	while (*p)
4141 	{
4142 		if (strcasecmp( (*p)->addr, a) > 0)
4143 			break;
4144 		p= &(*p)->next;
4145 	}
4146 
4147 	q->next= *p;
4148 	*p=q;
4149 	return (0);
4150 }
4151 
save_listacl_names(const char * addr,const char * name,void * vp)4152 static int save_listacl_names(const char *addr, const char *name,
4153 			      void *vp)
4154 {
4155 	struct acl_list *p=(struct acl_list *)vp;
4156 
4157 	for ( ; name && p; p=p->next)
4158 		if (strcasecmp(p->addr, addr) == 0 && p->name == 0)
4159 			p->name=strdup(name);
4160 	return (0);
4161 }
4162 
sqpcp_eventacl()4163 void sqpcp_eventacl()
4164 {
4165 	const char *p;
4166 	struct acl_list *acl_list=NULL;
4167 	struct PCP *pcp;
4168 	struct acl_list *pp;
4169 
4170 	if (!sqpcp_has_groupware())
4171 		return;
4172 
4173 	p=cgi("addemail");
4174 
4175 	while (*p && isspace((int)(unsigned char)*p))
4176 		++p;
4177 
4178 	if (!*p)
4179 		p=cgi("addressbookname");
4180 
4181 	if (*p)
4182 		addacl(p);
4183 
4184 	pcp=sqpcp_calendar();
4185 
4186 	if (!pcp)
4187 		return;
4188 
4189 	if (*(p=cgi("remove")))
4190 	{
4191 		if (pcp_acl(pcp, p, 0))
4192 		{
4193 			saveerror(pcp, NULL);
4194 			showerror();
4195 		}
4196 	}
4197 
4198 	if (pcp_list_acl(pcp, listacl, &acl_list))
4199 	{
4200 		saveerror(pcp, NULL);
4201 		showerror();
4202 	}
4203 	else if (ab_get_nameaddr(save_listacl_names, acl_list))
4204 	{
4205 		int dummy=PCP_ERR_SYSERR;
4206 
4207 		saveerror(NULL, &dummy);
4208 		showerror();
4209 	}
4210 	else if (acl_list)
4211 	{
4212 		printf("<table align=\"center\">\n");
4213 
4214 		for (pp=acl_list; pp; pp=pp->next)
4215 		{
4216 			printf("<tr><td align=\"right\"><span class=\"tt\">");
4217 			if (pp->addr)
4218 				ab_nameaddr_show(pp->name, pp->addr);
4219 
4220 			printf("</span></td><td>-");
4221 			if (pp->flags & PCP_ACL_MODIFY)
4222 				printf("&nbsp;%s", getarg("MODIFY"));
4223 			if (pp->flags & PCP_ACL_CONFLICT)
4224 				printf("&nbsp;%s", getarg("CONFLICT"));
4225 			printf("</td><td><a href=\"");
4226 			output_scriptptrget();
4227 			printf("&amp;form=eventacl&amp;remove=");
4228 			output_urlencoded(pp->addr);
4229 			printf("\">%s</a></td></tr>\n", getarg("REMOVE"));
4230 		}
4231 		printf("</table>\n");
4232 	}
4233 
4234 	while ((pp=acl_list) != NULL)
4235 	{
4236 		acl_list=pp->next;
4237 		if (pp->addr)
4238 			free(pp->addr);
4239 		if (pp->name)
4240 			free(pp->name);
4241 		free(pp);
4242 	}
4243 }
4244 
addacl(const char * p)4245 static void addacl(const char *p)
4246 {
4247 	int flags=0;
4248 	struct PCP *pcp;
4249 
4250 	if (strchr(p, '@') == NULL)
4251 	{
4252 		const char *mhn=myhostname();
4253 		char *q=malloc(strlen(p)+strlen(mhn)+2);
4254 
4255 		if (!q)
4256 			enomem();
4257 
4258 		strcat(strcat(strcpy(q, p), "@"), mhn);
4259 		addacl(q);
4260 		free(q);
4261 		return;
4262 	}
4263 
4264 	if (*cgi("aclMODIFY"))
4265 		flags |= PCP_ACL_MODIFY;
4266 
4267 	if (*cgi("aclCONFLICT"))
4268 		flags |= PCP_ACL_CONFLICT;
4269 
4270 	if (!flags)
4271 		return;	/* Noop */
4272 
4273 	pcp=sqpcp_calendar();
4274 
4275 	if (!pcp)
4276 	{
4277 		int xerror=PCP_ERR_SYSERR;
4278 
4279 		saveerror(NULL, &xerror);
4280 		showerror();
4281 		return;
4282 	}
4283 
4284 	if (!pcp_has_acl(pcp))
4285 	{
4286 		printf("%s\n", getarg("NOACL"));
4287 		return;
4288 	}
4289 
4290 	if (pcp_acl(pcp, p, flags))
4291 	{
4292 		saveerror(pcp, NULL);
4293 		showerror();
4294 		return;
4295 	}
4296 }
4297