1 /*
2 ** Copyright 2001-2009 Double Precision, Inc.  See COPYING for
3 ** distribution information.
4 */
5 
6 static const char rcsid[]="$Id: pcp.c,v 1.10 2009/11/08 18:14:47 mrsam Exp $";
7 
8 #include "config.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <errno.h>
14 #include <signal.h>
15 #include <unistd.h>
16 #include <langinfo.h>
17 #if HAVE_TERMIOS_H
18 #include <termios.h>
19 #endif
20 #include <fcntl.h>
21 #include <locale.h>
22 #include <libintl.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <pwd.h>
28 #include <rfc822/rfc822.h>
29 #include <rfc822/rfc2047.h>
30 #include <rfc822/rfc822hdr.h>
31 #include <rfc2045/rfc2045.h>
32 #include <rfc2045/rfc2045charset.h>
33 #include <unicode/unicode.h>
34 #include <numlib/numlib.h>
35 
36 #define PCP_ERRMSG(s) gettext(s)
37 
38 #include "pcp.h"
39 #include "calendardir.h"
40 
41 #define FLAG_LIST_EVENT_ID	1
42 
43 static const char *charset=RFC2045CHARSET;
44 
rfc2045_enomem()45 void rfc2045_enomem()
46 {
47 	fprintf(stderr, "Out of memory.\n");
48 	exit(1);
49 }
50 
51 PCP_STRERROR
52 
parse_datetime(int * argn,int argc,char ** argv)53 static time_t parse_datetime(int *argn, int argc, char **argv)
54 {
55 	struct pcp_parse_datetime_info pdi;
56 
57 	memset(&pdi, 0, sizeof(pdi));
58 
59 	pdi.today_name=gettext("today");
60 	pdi.tomorrow_name=gettext("tomorrow");
61 
62 	return (pcp_parse_datetime(argn, argc, argv, &pdi));
63 }
64 
from_s()65 static const char *from_s()
66 {
67 	return (gettext("from"));
68 }
69 
to_s()70 static const char *to_s()
71 {
72 	return (gettext("to"));
73 }
74 
event_s()75 static const char *event_s()
76 {
77 	return (gettext("event"));
78 }
79 
on_s()80 static const char *on_s()
81 {
82 	return (gettext("on"));
83 }
84 
error(struct PCP * pcp,int n,const char * s)85 static void error(struct PCP *pcp, int n, const char *s)
86 {
87 	const char *p;
88 
89 	p=pcp_strerror(n);
90 
91 	if (p)
92 		fprintf(stderr, "%s: %s\n", s, p);
93 	else
94 		fprintf(stderr, "%s: %s\n", s, pcp_errmsg(pcp));
95 }
96 
97 struct event_time_list {
98 	struct event_time_list *next;
99 	struct PCP_event_time thetime;
100 } ;
101 
save_time(time_t start,time_t end,void * vp)102 static int save_time(time_t start, time_t end, void *vp)
103 {
104 	struct event_time_list **ptr=(struct event_time_list **)vp;
105 	struct event_time_list *etl=
106 		(struct event_time_list *)
107 		malloc(sizeof(struct event_time_list));
108 
109 	if (!etl)
110 	{
111 		perror("malloc");
112 		exit(1);
113 	}
114 
115 	for (; *ptr; ptr=&(*ptr)->next)
116 				;
117 	*ptr=etl;
118 	etl->next=NULL;
119 
120 	etl->thetime.start=start;
121 	etl->thetime.end=end;
122 	return (0);
123 }
124 
125 
126 struct participant_list {
127 	struct participant_list *next;
128 	struct PCP_event_participant participant;
129 } ;
130 
131 static void usage();
132 
do_getpw()133 static struct passwd *do_getpw()
134 {
135 	struct passwd *pw=getpwuid(getuid());
136 
137 	if (!pw)
138 	{
139 		perror("getpwuid");
140 		exit(1);
141 	}
142 	return(pw);
143 }
144 
open_calendar()145 struct PCP *open_calendar()
146 {
147 	struct PCP *pcp;
148 	struct passwd *pw=do_getpw();
149 	char *p;
150 	const char *cp;
151 	FILE *fp;
152 	char authtoken[1024];
153 
154 	p=malloc(strlen(pw->pw_dir)+sizeof("/.pcplogin"));
155 	if (!p)
156 	{
157 		perror("malloc");
158 		exit(1);
159 	}
160 
161 	strcat(strcpy(p, pw->pw_dir), "/.pcplogin");
162 
163 	if ((fp=fopen(p, "r")) != NULL)
164 	{
165 		if (fgets(authtoken, sizeof(authtoken)-2, fp) != NULL)
166 		{
167 			char *q=authtoken+strlen(authtoken);
168 
169 			if (fgets(q, sizeof(authtoken)- (q-authtoken), fp)
170 			    != NULL)
171 			{
172 				char *userid=strtok(authtoken, "\n");
173 				const char *cp;
174 
175 				if (userid)
176 				{
177 					char *password=strtok(NULL, "\n");
178 					char *errmsg;
179 
180 					fclose(fp);
181 
182 					pcp=pcp_reopen_server(userid,
183 							      password,
184 							      &errmsg);
185 
186 					if (!pcp)
187 					{
188 						printf(gettext("LOGIN ERROR:\n%s\n"),
189 						       errmsg ?
190 						       errmsg:strerror(errno));
191 						if (errmsg)
192 							free(errmsg);
193 						exit(1);
194 					}
195 
196 					cp=pcp_authtoken(pcp);
197 
198 					if (!cp)
199 					{
200 						fprintf(stderr, gettext("ERROR: Unable to obtain authentication token from the server.\n"));
201 						exit(1);
202 					}
203 
204 					umask(077);
205 
206 					if ((fp=fopen(p, "w")) == NULL)
207 					{
208 						perror(p);
209 						exit(1);
210 					}
211 
212 					fprintf(fp, "%s\n%s\n",
213 						userid,
214 						cp);
215 					if (fflush(fp) || ferror(fp)
216 					    || fclose(fp))
217 					{
218 						perror(p);
219 						unlink(p);
220 						exit(1);
221 					}
222 					free(p);
223 					return (pcp);
224 				}
225 			}
226 		}
227 		fclose(fp);
228 		unlink(p);
229 	}
230 
231 	if ((cp=getenv("PCPDIR")) != NULL && *cp)
232 	{
233 		free(p);
234 		p=strdup(cp);
235 		if (!p)
236 		{
237 			perror("strdup");
238 			exit(1);
239 		}
240 	}
241 	else
242 	{
243 		strcat(strcpy(p, pw->pw_dir), "/.pcp");
244 	}
245 
246 	if (mkdir(p, 0700) == 0)
247 	{
248 		fprintf(stderr, "pcp: created %s\n", p);
249 	}
250 
251 	pcp=pcp_open_dir(p, pw->pw_name);
252 	free(p);
253 
254 	if (!pcp)
255 	{
256 		perror("pcp_open_dir");
257 		exit(1);
258 	}
259 
260 	if (pcp_cleanup(pcp))
261 	{
262 		perror("pcp_cleanup");
263 		pcp_close(pcp);
264 		return (NULL);
265 	}
266 	return (pcp);
267 }
268 
269 /**** Add stuff to the calendar ****/
270 
271 struct add_info {
272 	int (*add_func)(struct add_info *);
273 	const char *add_charset;
274 	char *add_subject;
275 
276 	char *bufptr;
277 	int bufleft;
278 	char buffer[BUFSIZ];
279 
280 } ;
281 
282 static int add_info_callback(char *, int, void *);
283 
show_conflict(const char * event_id,time_t from,time_t to,const char * addr,void * dummy)284 static int show_conflict(const char *event_id,
285 			 time_t from,
286 			 time_t to,
287 			 const char *addr,
288 			 void *dummy)
289 {
290 	char buf[500];
291 
292 	if (pcp_fmttimerange(buf, sizeof(buf), from, to) < 0)
293 		buf[0]=0;
294 
295 	fprintf(stderr, gettext("Conflict: %s\n    (%s)\n"),
296 		buf, event_id);
297 	return (0);
298 }
299 
add(int argn,int argc,char ** argv,int flags,const char * old,struct add_info * add_info)300 static void add(int argn, int argc, char **argv, int flags, const char *old,
301 		struct add_info *add_info)
302 {
303 	struct event_time_list *list=NULL;
304 	struct participant_list *book=NULL;
305 
306 	const char *subject=NULL;
307 	struct PCP *pcp;
308 	struct PCP_new_eventid *nei;
309 	struct PCP_commit commit_info;
310 	struct PCP_save_event add_event_info;
311 
312 	while (argn < argc)
313 	{
314 		if (strcmp(argv[argn], gettext("with")) == 0)
315 		{
316 			struct participant_list **ptr;
317 
318 			++argn;
319 			if (argn >= argc)
320 				usage();
321 
322 			for (ptr= &book; *ptr; ptr= &(*ptr)->next)
323 				;
324 
325 			if ((*ptr=malloc(sizeof(struct participant_list)))
326 			    == NULL)
327 			{
328 				perror("malloc");
329 				exit(1);
330 			}
331 			(*ptr)->participant.address=argv[argn];
332 			(*ptr)->next=NULL;
333 			++argn;
334 			continue;
335 		}
336 
337 		if (strcasecmp(argv[argn], from_s()) == 0)
338 		{
339 			time_t from_time, to_time;
340 
341 			++argn;
342 			if ((from_time=parse_datetime(&argn, argc, argv))
343 			    == 0)
344 				usage();
345 
346 			if (argn < argc && strcasecmp(argv[argn], to_s()) == 0)
347 			{
348 				++argn;
349 				if ((to_time=parse_datetime(&argn, argc,
350 							    argv)) == 0)
351 					usage();
352 
353 				if (from_time > to_time)
354 					usage();
355 			}
356 			else
357 			{
358 				to_time=from_time + 60 * 60;
359 			}
360 
361 			if (argn < argc && strcmp(argv[argn],
362 						  gettext("until")) == 0)
363 			{
364 				++argn;
365 
366 				if (pcp_parse_datetime_until(from_time,
367 							     to_time,
368 							     &argn,
369 							     argc,
370 							     argv,
371 
372 							     PCP_RECURRING_WEEKLY,
373 							     &save_time,
374 							     &list))
375 					usage();
376 			}
377 			else
378 			{
379 				save_time(from_time, to_time, &list);
380 			}
381 			continue;
382 		}
383 
384 		if (strcmp(argv[argn], "subject") == 0)
385 		{
386 			if (subject || ++argn >= argc)
387 				usage();
388 			subject=argv[argn++];
389 			continue;
390 		}
391 		usage();
392 	}
393 
394 	memset(&commit_info, 0, sizeof(commit_info));
395 	commit_info.flags=flags;
396 
397 	{
398 		struct event_time_list *p;
399 		struct PCP_event_time *q=0;
400 
401 		for (p=list; p; p=p->next)
402 			++commit_info.n_event_times;
403 
404 		if (!commit_info.n_event_times)
405 			usage();
406 
407 		if ((commit_info.event_times=q=
408 		     calloc(commit_info.n_event_times,
409 			    sizeof(*commit_info.event_times))) == NULL)
410 		{
411 			perror("malloc");
412 			exit(1);
413 		}
414 		commit_info.n_event_times=0;
415 		for (p=list; p; p=p->next)
416 			q[commit_info.n_event_times++]=p->thetime;
417 	}
418 
419 	memset(&add_event_info, 0, sizeof(add_event_info));
420 	{
421 		struct participant_list *p;
422 		struct PCP_event_participant *q=0;
423 
424 		for (p=book; p; p=p->next)
425 			++add_event_info.n_event_participants;
426 
427 		if (add_event_info.n_event_participants &&
428 		    (add_event_info.event_participants=q=
429 		     calloc(add_event_info.n_event_participants,
430 			    sizeof(*add_event_info.event_participants)))
431 		    == NULL)
432 		{
433 			perror("malloc");
434 			exit(1);
435 			return;
436 		}
437 		add_event_info.n_event_participants=0;
438 
439 		for (p=book; p; p=p->next)
440 			q[add_event_info.n_event_participants++]
441 				=p->participant;
442 	}
443 
444 	add_event_info.write_event_func=add_info_callback;
445 	add_event_info.write_event_func_misc_ptr=add_info;
446 
447 	pcp=open_calendar();
448 
449 	nei=pcp_new_eventid(pcp, old, &add_event_info);
450 
451 	if (!nei)
452 	{
453 		pcp_close(pcp);
454 		perror("pcp_new_event_id");
455 		exit(1);
456 	}
457 
458 	commit_info.add_conflict_callback= &show_conflict;
459 	if (pcp_commit(pcp, nei, &commit_info))
460 	{
461 		error(pcp, commit_info.errcode, "pcp_commit");
462 		pcp_destroy_eventid(pcp, nei);
463 		pcp_close(pcp);
464 		exit(1);
465 	}
466 
467 	printf(gettext("Created event %s\n"), nei->eventid);
468 	pcp_destroy_eventid(pcp, nei);
469 	pcp_close(pcp);
470 	exit (0);
471 }
472 
add_info_callback(char * buf,int cnt,void * p)473 static int add_info_callback(char *buf, int cnt, void *p)
474 {
475 	struct add_info *ai=(struct add_info *)p;
476 	int n;
477 
478 	if (!ai->bufleft)
479 	{
480 		n= (*ai->add_func)(ai);
481 
482 		if (n < 0)
483 			return (n);
484 	}
485 	n=0;
486 	while (cnt && ai->bufleft)
487 	{
488 		*buf++ = *ai->bufptr++;
489 		--ai->bufleft;
490 		--cnt;
491 		++n;
492 	}
493 	return (n);
494 }
495 
add_read_stdin(struct add_info * p)496 static int add_read_stdin(struct add_info *p)
497 {
498 	int n=read(0, p->buffer, sizeof(p->buffer));
499 
500 	p->bufptr=p->buffer;
501 	if (n < 0)
502 		return (n);
503 	p->bufleft=n;
504 	return (0);
505 }
506 
add_read_stdin_prompt(struct add_info * p)507 static int add_read_stdin_prompt(struct add_info *p)
508 {
509 	p->add_func=add_read_stdin;
510 
511 	printf(gettext("\nEnter event information, terminate with EOF (usually CTRL-D)\n\n"));
512 	return (add_read_stdin(p));
513 }
514 
515 static int add_read_mime(struct add_info *p);
516 
add_read_subject(struct add_info * p)517 static int add_read_subject(struct add_info *p)
518 {
519 	strcpy(p->buffer, "Subject: ");
520 	strncat(p->buffer, p->add_subject, sizeof(p->buffer)-100);
521 	strcat(p->buffer, "\n");
522 	p->add_func= &add_read_mime;
523 	p->bufptr=p->buffer;
524 	p->bufleft=strlen(p->buffer);
525 	return (0);
526 }
527 
add_read_mime(struct add_info * p)528 static int add_read_mime(struct add_info *p)
529 {
530 	strcpy(p->buffer, "Mime-Version: 1.0\n"
531 	       "Content-Type: text/plain; charset=\"");
532 	strcat(p->buffer, p->add_charset);
533 	strcat(p->buffer, "\"\nContent-Transfer-Encoding: 8bit\n\n");
534 	p->add_func= add_read_stdin_prompt;
535 	p->bufptr=p->buffer;
536 	p->bufleft=strlen(p->buffer);
537 	return (0);
538 }
539 
540 /**** List calendar ****/
541 
542 static int list_callback_saveindex(struct PCP_list_all *, void *);
543 
544 struct listinfo {
545 	time_t list_from;
546 	time_t list_to;
547 	const char *list_event_id;
548 	int cnt;
549 	struct listinfo_index *index_list;
550 	unsigned i_cnt;
551 } ;
552 
553 struct listinfo_index {
554 	struct listinfo_index *next;
555 	size_t from;
556 	size_t to;
557 	char *subject;
558 	char *eventid;
559 	int status;
560 } ;
561 
indexcmp(const void * a,const void * b)562 static int indexcmp(const void *a, const void *b)
563 {
564 	struct listinfo_index *ap=*(struct listinfo_index * const *)a;
565 	struct listinfo_index *bp=*(struct listinfo_index * const *)b;
566 
567 	return ( ap->from < bp->from ? -1:
568 		 ap->from > bp->from ? 1:
569 		 ap->to < bp->to ? -1:
570 		 ap->to > bp->to ? 1:0);
571 }
572 
573 static void doretr(const char *);
574 
575 static int save_retr_headers(struct PCP_retr *, const char *,
576 			     const char *, void *);
577 static int save_retr_status(struct PCP_retr *, int, void *);
578 
dump_rfc822_hdr(const char * ptr,size_t cnt,void * dummy)579 static void dump_rfc822_hdr(const char *ptr, size_t cnt,
580 			    void *dummy)
581 {
582 	fwrite(ptr, cnt, 1, stdout);
583 }
584 
585 
list(int argn,int argc,char ** argv,int flags)586 static void list(int argn, int argc, char **argv, int flags)
587 {
588 	struct listinfo listinfo;
589 	int all_flag=0;
590 	int showevent=0;
591 	struct PCP *pcp;
592 	struct PCP_list_all list_all;
593 
594 	memset(&listinfo, 0, sizeof(listinfo));
595 	memset(&list_all, 0, sizeof(list_all));
596 
597 	while (argn < argc)
598 	{
599 		if (strcasecmp(argv[argn], gettext("all")) == 0)
600 		{
601 			all_flag=1;
602 			++argn;
603 			continue;
604 		}
605 
606 		if (strcasecmp(argv[argn], on_s()) == 0)
607 		{
608 			++argn;
609 			if (listinfo.list_from ||
610 			    listinfo.list_to ||
611 			    (listinfo.list_from=
612 			     listinfo.list_to=
613 			     parse_datetime(&argn, argc, argv)) == 0)
614 				usage();
615 			showevent=1;
616 			continue;
617 		}
618 
619 		if (strcasecmp(argv[argn], from_s()) == 0)
620 		{
621 			++argn;
622 			if (listinfo.list_from != 0 ||
623 			    (listinfo.list_from=
624 			     parse_datetime(&argn, argc, argv)) == 0)
625 				usage();
626 			continue;
627 		}
628 
629 		if (strcasecmp(argv[argn], to_s()) == 0)
630 		{
631 			++argn;
632 			if (listinfo.list_to != 0 ||
633 			    (listinfo.list_to=
634 			     parse_datetime(&argn, argc, argv)) == 0)
635 				usage();
636 			continue;
637 		}
638 
639 		if (strcasecmp(argv[argn], event_s()) == 0)
640 		{
641 			++argn;
642 			if (argn >= argc || listinfo.list_event_id)
643 				usage();
644 			listinfo.list_event_id=argv[argn++];
645 			continue;
646 		}
647 		usage();
648 	}
649 
650 	/* If neither start-end, nor "all" is specified, list events
651 	   for today */
652 
653 	if (!all_flag && listinfo.list_from == 0 &&
654 	    listinfo.list_to == 0 && !listinfo.list_event_id)
655 	{
656 		time_t t;
657 		struct tm *tmptr;
658 
659 		time(&t);
660 		tmptr=localtime(&t);
661 
662 		pcp_parse_ymd(tmptr->tm_year + 1900,
663 			      tmptr->tm_mon + 1,
664 			      tmptr->tm_mday,
665 			      &listinfo.list_from,
666 			      &listinfo.list_to);
667 	}
668 
669 	if ((listinfo.list_from || listinfo.list_to)
670 	    && listinfo.list_event_id)
671 	usage();
672 
673 	if (listinfo.list_event_id)
674 	{
675 		doretr(listinfo.list_event_id);
676 		return;
677 	}
678 
679 	pcp=open_calendar();
680 
681 	list_all.callback_func=list_callback_saveindex;
682 	list_all.callback_arg= &listinfo;
683 	list_all.list_from=listinfo.list_from;
684 	list_all.list_to=listinfo.list_to;
685 	listinfo.i_cnt=0;
686 	if (pcp_list_all(pcp, &list_all))
687 	{
688 		perror("pcp_xlist");
689 		pcp_close(pcp);
690 		exit(1);
691 	}
692 
693 	/* Show event index */
694 
695 	if (listinfo.index_list)
696 	{
697 		unsigned cnt=0, i, maxl;
698 		struct listinfo_index *p, **ary;
699 		const char **event_id_list;
700 		struct PCP_retr r;
701 
702 		for (p=listinfo.index_list; p; p=p->next)
703 			++cnt;
704 
705 		event_id_list=(const char **)
706 			malloc(sizeof(const char *)*(cnt+1));
707 		if (!event_id_list)
708 		{
709 			perror("malloc");
710 			exit(1);
711 		}
712 		cnt=0;
713 
714 		for (p=listinfo.index_list; p; p=p->next)
715 			event_id_list[cnt++]=p->eventid;
716 		event_id_list[cnt]=0;
717 		memset(&r, 0, sizeof(r));
718 		r.callback_arg=&listinfo;
719 
720 		r.callback_retr_status=save_retr_status;
721 		r.callback_arg=&listinfo;
722 		r.event_id_list=event_id_list;
723 
724 		if (pcp_retr(pcp, &r))
725 		{
726 			error(pcp, r.errcode, "pcp_retr");
727 			pcp_close(pcp);
728 			exit(1);
729 		}
730 
731 		r.callback_headers_func=save_retr_headers;
732 
733 		if (pcp_retr(pcp, &r))
734 		{
735 			error(pcp, r.errcode, "pcp_retr");
736 			pcp_close(pcp);
737 			exit(1);
738 		}
739 
740 		free(event_id_list);
741 
742 		ary=(struct listinfo_index **)
743 			malloc(sizeof(struct listinfo_index *)
744 			       * listinfo.i_cnt);
745 
746 		if (!ary)
747 		{
748 			perror("malloc");
749 			pcp_close(pcp);
750 			exit(1);
751 		}
752 
753 		cnt=0;
754 		for (p=listinfo.index_list; p; p=p->next)
755 			ary[cnt++]=p;
756 		qsort(ary, cnt, sizeof(ary[0]), indexcmp);
757 
758 		maxl=20;
759 
760 		for (i=0; i<cnt; i++)
761 		{
762 			char fromto[500];
763 
764 			if (pcp_fmttimerange(fromto, sizeof(fromto),
765 					     ary[i]->from,
766 					     ary[i]->to) == 0 &&
767 			    strlen(fromto) > maxl)
768 				maxl=strlen(fromto);
769 		}
770 
771 		for (i=0; i<cnt; i++)
772 		{
773 			char fromto[500];
774 
775 			if (pcp_fmttimerange(fromto, sizeof(fromto),
776 					     ary[i]->from,
777 					     ary[i]->to) < 0)
778 				strcpy(fromto, "******");
779 			printf("%-*s %s%s", (int)maxl, fromto,
780 			       ary[i]->status & LIST_CANCELLED
781 			       ? gettext("CANCELLED: "):"",
782 			       ary[i]->status & LIST_BOOKED
783 			       ? gettext("(event not yet commited) "):"");
784 
785 			if (rfc822_display_hdrvalue("subject",
786 						    ary[i]->subject
787 						    ? ary[i]->subject:"",
788 						    charset,
789 						    dump_rfc822_hdr,
790 						    NULL, NULL) < 0)
791 			{
792 				printf("%s",
793 				       ary[i]->subject
794 				       ? ary[i]->subject:"");
795 			}
796 			printf("\n");
797 
798 			if (flags & FLAG_LIST_EVENT_ID)
799 				printf("%-*s(%s)\n", (int)maxl, "",
800 				       ary[i]->eventid);
801 		}
802 		free(ary);
803 		listinfo.cnt=cnt;
804 	}
805 
806 	printf(gettext("%d events found.\n"), listinfo.cnt);
807 
808 	while (listinfo.index_list)
809 	{
810 		struct listinfo_index *p=listinfo.index_list;
811 
812 		listinfo.index_list=p->next;
813 		free(p->eventid);
814 		if (p->subject)
815 			free(p->subject);
816 		free(p);
817 	}
818 	pcp_close(pcp);
819 }
820 
list_callback_saveindex(struct PCP_list_all * xl,void * vp)821 static int list_callback_saveindex(struct PCP_list_all *xl, void *vp)
822 {
823 	struct listinfo *li=(struct listinfo *)vp;
824 	struct listinfo_index *i;
825 
826 	li->cnt++;
827 
828 	if ((i=(struct listinfo_index *)
829 	     malloc(sizeof(struct listinfo_index))) == NULL)
830 	{
831 		perror("malloc");
832 		exit(1);
833 	}
834 	memset(i, 0, sizeof(*i));
835 
836 	if ((i->eventid=strdup(xl->event_id)) == NULL)
837 	{
838 		free(i);
839 		perror("malloc");
840 		exit(1);
841 	}
842 
843 	i->next=li->index_list;
844 	li->index_list=i;
845 	++li->i_cnt;
846 	i->from=xl->event_from;
847 	i->to=xl->event_to;
848 	i->subject=NULL;
849 	return (0);
850 }
851 
save_retr_status(struct PCP_retr * r,int status,void * vp)852 static int save_retr_status(struct PCP_retr *r, int status, void *vp)
853 {
854 	struct listinfo *l=(struct listinfo *)vp;
855 	struct listinfo_index *i;
856 
857 	for (i=l->index_list; i; i=i->next)
858 		if (strcmp(i->eventid, r->event_id) == 0)
859 		{
860 			i->status=status;
861 		}
862 	return (0);
863 }
864 
save_retr_headers(struct PCP_retr * ri,const char * h,const char * v,void * vp)865 static int save_retr_headers(struct PCP_retr *ri, const char *h,
866 			     const char *v, void *vp)
867 {
868 	struct listinfo *l=(struct listinfo *)vp;
869 	struct listinfo_index *i;
870 	char *p, *q;
871 
872 	if (strcasecmp(h, "subject"))
873 		return (0);
874 
875 	for (i=l->index_list; i; i=i->next)
876 		if (strcmp(i->eventid, ri->event_id) == 0)
877 		{
878 			if (!i->subject)
879 			{
880 				i->subject=strdup(v);
881 				if (!i->subject)
882 					return (-1);
883 			}
884 
885 			for (p=q=i->subject; *p; )
886 			{
887 				if (*p == '\n')
888 				{
889 					while (*p && isspace((int)
890 							     (unsigned char)
891 							     *p))
892 						++p;
893 					*q++=' ';
894 					continue;
895 				}
896 				*q++ = *p++;
897 			}
898 			*q=0;
899 		}
900 	return (0);
901 }
902 
903 static int doretr_begin(struct PCP_retr *r, void *vp);
904 static int doretr_save(struct PCP_retr *, const char *, int, void *);
905 static int do_show_retr(struct PCP_retr *, void *);
906 
907 struct xretrinfo {
908 	FILE *tmpfile;
909 	int status;
910 	struct xretr_participant_list *participant_list;
911 	struct xretr_time_list *time_list;
912 
913 } ;
914 
915 struct xretr_participant_list {
916 	struct xretr_participant_list *next;
917 	char *participant;
918 } ;
919 
920 struct xretr_time_list {
921 	struct xretr_time_list *next;
922 	time_t from;
923 	time_t to;
924 } ;
925 
doretr_status(struct PCP_retr * p,int status,void * vp)926 static int doretr_status(struct PCP_retr *p, int status, void *vp)
927 {
928 	struct xretrinfo *xr=(struct xretrinfo *)vp;
929 
930 	xr->status=status;
931 	return (0);
932 }
933 
doretr_date(struct PCP_retr * p,time_t from,time_t to,void * vp)934 static int doretr_date(struct PCP_retr *p, time_t from, time_t to, void *vp)
935 {
936 	struct xretrinfo *xr=(struct xretrinfo *)vp;
937 	struct xretr_time_list *t=malloc(sizeof(struct xretr_time_list));
938 
939 	if (!t)
940 		return (-1);
941 
942 	t->next=xr->time_list;
943 	xr->time_list=t;
944 	t->from=from;
945 	t->to=to;
946 	return (0);
947 }
948 
doretr_participants(struct PCP_retr * p,const char * n,const char * id,void * vp)949 static int doretr_participants(struct PCP_retr *p, const char *n,
950 			       const char *id, void *vp)
951 {
952 	struct xretrinfo *xr=(struct xretrinfo *)vp;
953 	char *s=strdup(n);
954 	struct xretr_participant_list *pa;
955 
956 	if (!s)
957 		return (-1);
958 
959 	if ((pa=malloc(sizeof(struct xretr_participant_list))) == NULL)
960 	{
961 		free(s);
962 		return (-1);
963 	}
964 	pa->participant=s;
965 	pa->next=xr->participant_list;
966 	xr->participant_list=pa;
967 	return (0);
968 }
969 
doretr(const char * eventid)970 static void doretr(const char *eventid)
971 {
972 	struct PCP *pcp;
973 	struct PCP_retr r;
974 	struct xretrinfo xr;
975 	const char *event_id_array[2];
976 	struct xretr_time_list *tl;
977 	struct xretr_participant_list *pl;
978 
979 	pcp=open_calendar();
980 
981 	memset(&r, 0, sizeof(r));
982 	memset(&xr, 0, sizeof(xr));
983 
984 	r.callback_arg= &xr;
985 	r.callback_retr_status=doretr_status;
986 	r.callback_retr_date=doretr_date;
987 	r.callback_retr_participants=doretr_participants;
988 
989 	event_id_array[0]=eventid;
990 	event_id_array[1]=NULL;
991 
992 	r.event_id_list=event_id_array;
993 
994 	if (pcp_retr(pcp, &r) == 0)
995 	{
996 		r.callback_retr_status=NULL;
997 		r.callback_retr_date=NULL;
998 		r.callback_retr_participants=NULL;
999 
1000 		r.callback_begin_func=doretr_begin;
1001 		r.callback_rfc822_func=doretr_save;
1002 		r.callback_end_func=do_show_retr;
1003 		if (pcp_retr(pcp, &r) == 0)
1004 		{
1005 			pcp_close(pcp);
1006 		}
1007 		else
1008 		{
1009 			error(pcp, r.errcode, "pcp_retr");
1010 			pcp_close(pcp);
1011 		}
1012 	}
1013 	else
1014 	{
1015 		error(pcp, r.errcode, "pcp_retr");
1016 		pcp_close(pcp);
1017 	}
1018 
1019 	while ((pl=xr.participant_list) != NULL)
1020 	{
1021 		xr.participant_list=pl->next;
1022 		free(pl->participant);
1023 		free(pl);
1024 	}
1025 
1026 	while ((tl=xr.time_list) != NULL)
1027 	{
1028 		xr.time_list=tl->next;
1029 		free(tl);
1030 	}
1031 }
1032 
doretr_begin(struct PCP_retr * r,void * vp)1033 static int doretr_begin(struct PCP_retr *r, void *vp)
1034 {
1035 	struct xretrinfo *xr=(struct xretrinfo *)vp;
1036 
1037 	if ((xr->tmpfile=tmpfile()) == NULL)
1038 		return (-1);
1039 	return (0);
1040 }
1041 
doretr_save(struct PCP_retr * r,const char * p,int n,void * vp)1042 static int doretr_save(struct PCP_retr *r, const char *p, int n, void *vp)
1043 {
1044 	struct xretrinfo *xr=(struct xretrinfo *)vp;
1045 
1046 	if (fwrite(p, n, 1, xr->tmpfile) != 1)
1047 		return (-1);
1048 	return (0);
1049 }
1050 
tcmp(const void * a,const void * b)1051 static int tcmp(const void *a, const void *b)
1052 {
1053 	struct xretr_time_list *ap=*(struct xretr_time_list **)a;
1054 	struct xretr_time_list *bp=*(struct xretr_time_list **)b;
1055 
1056 	return ( ap->from < bp->from ? -1:
1057 		 ap->from > bp->from ? 1:
1058 		 ap->to < bp->to ? -1:
1059 		 ap->to > bp->to ? 1:0);
1060 }
1061 
1062 static int list_msg_rfc822(struct rfc2045 *, FILE *);
1063 
do_show_retr(struct PCP_retr * r,void * vp)1064 static int do_show_retr(struct PCP_retr *r, void *vp)
1065 {
1066 	struct xretrinfo *xr=(struct xretrinfo *)vp;
1067 	struct xretr_participant_list *p;
1068 	struct xretr_time_list *t, **tt;
1069 	unsigned cnt, i;
1070 	struct rfc2045 *rfcp;
1071 	int rc;
1072 
1073 	if (fseek(xr->tmpfile, 0L, SEEK_SET) < 0
1074 	    || lseek(fileno(xr->tmpfile), 0L, SEEK_SET) < 0)
1075 	{
1076 		fclose(xr->tmpfile);
1077 		return (-1);
1078 	}
1079 
1080 	if (xr->time_list == NULL)
1081 	{
1082 		fclose(xr->tmpfile);
1083 		return (0);
1084 	}
1085 
1086 	printf(gettext("Event: %s\n"), r->event_id);
1087 
1088 	for (cnt=0, t=xr->time_list; t; t=t->next)
1089 		++cnt;
1090 
1091 	tt=(struct xretr_time_list **)malloc(cnt * sizeof(*t));
1092 	if (!tt)
1093 	{
1094 		fclose(xr->tmpfile);
1095 		return (-1);
1096 	}
1097 
1098 	for (cnt=0, t=xr->time_list; t; t=t->next)
1099 		tt[cnt++]=t;
1100 
1101 	qsort(tt, cnt, sizeof(*tt), tcmp);
1102 
1103 	for (i=0; i<cnt; i++)
1104 	{
1105 		char fromto[500];
1106 
1107 		if (pcp_fmttimerange(fromto, sizeof(fromto),
1108 				     tt[i]->from, tt[i]->to) < 0)
1109 			strcpy(fromto, "******");
1110 		printf(gettext("       %s\n"), fromto);
1111 	}
1112 	free(tt);
1113 
1114 	if (xr->status & LIST_CANCELLED)
1115 		printf(gettext("    **** CANCELLED ****\n"));
1116 	if (xr->status & LIST_BOOKED)
1117 		printf(gettext("    **** EVENT NOT YET COMMITED ****\n"));
1118 
1119 	for (p=xr->participant_list; p; p=p->next)
1120 		printf(gettext("    Participant: %s\n"), p->participant);
1121 
1122 
1123 	rfcp=rfc2045_fromfp(xr->tmpfile);
1124 	if (!rfcp)
1125 	{
1126 		fclose(xr->tmpfile);
1127 		return (-1);
1128 	}
1129 
1130 	rc=list_msg_rfc822(rfcp, xr->tmpfile);
1131 	rfc2045_free(rfcp);
1132 	fclose(xr->tmpfile);
1133 	return (rc);
1134 }
1135 
1136 static int list_msg_mime(struct rfc2045 *, FILE *);
1137 
list_msg_rfc822(struct rfc2045 * rfc,FILE * fp)1138 static int list_msg_rfc822(struct rfc2045 *rfc, FILE *fp)
1139 {
1140 	off_t   start_pos, end_pos, start_body;
1141 	off_t	dummy, pos;
1142 	struct rfc822hdr h;
1143 
1144         rfc2045_mimepos(rfc, &start_pos, &end_pos, &start_body,
1145 			&dummy, &dummy);
1146         if (fseek(fp, start_pos, SEEK_SET) < 0)
1147 		return (-1);
1148 
1149 	pos=start_pos;
1150 	rfc822hdr_init(&h, 8192);
1151 
1152 	while (rfc822hdr_read(&h, fp, &pos, start_body) == 0)
1153 	{
1154 		printf("%s: ", h.header);
1155 
1156 		if (rfc822_display_hdrvalue(h.header, h.value, charset,
1157 					    dump_rfc822_hdr, NULL, NULL) < 0)
1158 		{
1159 			printf("%s", h.value);
1160 		}
1161 
1162 		printf("\n");
1163 	}
1164 	rfc822hdr_free(&h);
1165 	printf("\n");
1166 	return (list_msg_mime(rfc, fp));
1167 }
1168 
list_msg_rfc822_part(struct rfc2045 * rfc,FILE * fp)1169 static int list_msg_rfc822_part(struct rfc2045 *rfc, FILE *fp)
1170 {
1171 	struct rfc2045 *q;
1172 
1173 	for (q=rfc->firstpart; q; q=q->next)
1174 	{
1175 		if (q->isdummy) continue;
1176 		return (list_msg_rfc822(q, fp));
1177 	}
1178 	return (0);
1179 }
1180 
1181 
1182 static int list_msg_mime_multipart(struct rfc2045 *, FILE *);
1183 static int list_msg_mime_multipart_alternative(struct rfc2045 *, FILE *);
1184 static int list_msg_textplain(struct rfc2045 *, FILE *);
1185 
mime_handler(struct rfc2045 * rfc)1186 static int (*mime_handler(struct rfc2045 *rfc))(struct rfc2045 *, FILE *)
1187 {
1188 	const char      *content_type, *dummy;
1189 
1190         rfc2045_mimeinfo(rfc, &content_type, &dummy, &dummy);
1191         if (strcmp(content_type, "multipart/alternative") == 0)
1192 		return ( &list_msg_mime_multipart_alternative);
1193         if (strncmp(content_type, "multipart/", 10) == 0)
1194 		return ( &list_msg_mime_multipart);
1195 
1196         if (strcmp(content_type, "message/rfc822") == 0)
1197 		return ( &list_msg_rfc822_part );
1198 
1199         if (strcmp(content_type, "text/plain") == 0
1200 	    || strcmp(content_type, "text/rfc822-headers") == 0
1201 	    || strcmp(content_type, "message/delivery-status") == 0)
1202 		return ( &list_msg_textplain);
1203 	return (NULL);
1204 }
1205 
1206 
list_msg_mime(struct rfc2045 * rfc,FILE * fp)1207 static int list_msg_mime(struct rfc2045 *rfc, FILE *fp)
1208 {
1209 	int (*handler)(struct rfc2045 *, FILE *)=
1210 		mime_handler(rfc);
1211 	const char      *content_type, *dummy;
1212 
1213 
1214 	char *disposition_name;
1215 	char *disposition_filename;
1216 	char *content_name;
1217 
1218 	const char *disposition_filename_s;
1219 
1220 	off_t start_pos, end_pos, start_body;
1221 	off_t dummy2;
1222 	char buffer[NUMBUFSIZE+10];
1223 
1224 	if (handler)
1225 		return ( (*handler)(rfc, fp));
1226 
1227         rfc2045_mimeinfo(rfc, &content_type, &dummy, &dummy);
1228 
1229 	if (rfc2231_udecodeDisposition(rfc, "name", NULL, &disposition_name)<0
1230 	    ||
1231 	    rfc2231_udecodeDisposition(rfc, "filename", NULL,
1232 				       &disposition_filename) < 0
1233 	    ||
1234 	    rfc2231_udecodeType(rfc, "name", NULL,
1235 				&content_name) < 0)
1236 	{
1237 		perror("malloc");
1238 		exit(1);
1239 	}
1240 
1241         rfc2045_mimepos(rfc, &start_pos, &end_pos, &start_body,
1242                         &dummy2, &dummy2);
1243 
1244 	disposition_filename_s=disposition_filename;
1245 
1246 	if (!*disposition_filename_s)
1247 		disposition_filename_s=content_name;
1248 	if (!disposition_filename_s || !*disposition_filename_s)
1249 		disposition_filename_s=disposition_name;
1250 
1251 	printf(gettext("Attachment: %s (%s)\n"), content_type,
1252 	       libmail_str_sizekb(end_pos - start_body, buffer));
1253 	if (disposition_filename_s && *disposition_filename_s)
1254 		printf("    %s\n", disposition_filename_s);
1255 	printf("\n");
1256 
1257 	free(content_name);
1258 	free(disposition_name);
1259 	free(disposition_filename);
1260 	return (0);
1261 }
1262 
list_msg_mime_multipart(struct rfc2045 * rfc,FILE * fp)1263 static int list_msg_mime_multipart(struct rfc2045 *rfc, FILE *fp)
1264 {
1265 	struct rfc2045 *q;
1266 	int first=1;
1267 	int rc;
1268 
1269 	for (q=rfc->firstpart; q; q=q->next)
1270 	{
1271 		if (q->isdummy) continue;
1272 
1273 		if (!first)
1274 			printf("\n    ------------------------------\n\n");
1275 		first=0;
1276 
1277 		rc=list_msg_mime(q, fp);
1278 		if (rc)
1279 			return (rc);
1280 	}
1281 	return (0);
1282 }
1283 
list_msg_mime_multipart_alternative(struct rfc2045 * rfc,FILE * fp)1284 static int list_msg_mime_multipart_alternative(struct rfc2045 *rfc, FILE *fp)
1285 {
1286 	struct rfc2045 *q, *first=NULL, *last=NULL;
1287 
1288 	for (q=rfc->firstpart; q; q=q->next)
1289 	{
1290 		if (q->isdummy) continue;
1291 		if (!first)
1292 			first=q;
1293 		if ( mime_handler(q) != NULL)
1294 			last=q;
1295 	}
1296 
1297 	return (last ? list_msg_mime(last, fp):
1298 		first ? list_msg_mime(first, fp):0);
1299 }
1300 
textplain_output(const char * ptr,size_t cnt,void * voidptr)1301 static int textplain_output(const char *ptr, size_t cnt, void *voidptr)
1302 {
1303 	while (cnt)
1304 	{
1305 		putchar(*ptr);
1306 		++ptr;
1307 		--cnt;
1308 	}
1309 	return (0);
1310 }
1311 
list_msg_textplain(struct rfc2045 * rfc,FILE * fp)1312 static int list_msg_textplain(struct rfc2045 *rfc, FILE *fp)
1313 {
1314 	const char *mime_charset, *dummy;
1315 	int rc;
1316 
1317         rfc2045_mimeinfo(rfc, &dummy, &dummy, &mime_charset);
1318 
1319         if (strcasecmp(mime_charset, charset) &&
1320             strcasecmp(mime_charset, "us-ascii"))
1321         {
1322 		printf(gettext("    (%s charset follows)\n\n"),
1323 		       mime_charset);
1324 	}
1325 
1326 	rc=rfc2045_decodetextmimesection(fileno(fp),
1327 					 rfc,
1328 					 charset,
1329 					 textplain_output, NULL);
1330 
1331 	printf("\n");
1332 	return (rc);
1333 }
1334 
1335 /*** CANCEL/UNCANCEL/DELETE ***/
1336 
docancel(const char * id,int flags)1337 static void docancel(const char *id, int flags)
1338 {
1339 	struct PCP *pcp=open_calendar();
1340 	int errcode;
1341 
1342 	if (pcp_cancel(pcp, id, &errcode))
1343 	{
1344 		error(pcp, errcode, "pcp_cancel");
1345 		exit(1);
1346 	}
1347 	pcp_close(pcp);
1348 }
1349 
dodelete(const char * id,int flags)1350 static void dodelete(const char *id, int flags)
1351 {
1352 	struct PCP *pcp=open_calendar();
1353 	struct PCP_delete del;
1354 
1355 	memset(&del, 0, sizeof(del));
1356 	del.id=id;
1357 
1358 	if (pcp_delete(pcp, &del))
1359 	{
1360 		error(pcp, del.errcode, "pcp_delete");
1361 		exit(1);
1362 	}
1363 	pcp_close(pcp);
1364 }
1365 
douncancel(const char * id,int flags)1366 static void douncancel(const char *id, int flags)
1367 {
1368 	struct PCP *pcp=open_calendar();
1369 	struct PCP_uncancel uncancel_info;
1370 
1371 	uncancel_info.uncancel_conflict_callback= &show_conflict;
1372 	uncancel_info.uncancel_conflict_callback_ptr=NULL;
1373 
1374 	if (pcp_uncancel(pcp, id, flags, &uncancel_info))
1375 	{
1376 		error(pcp, uncancel_info.errcode, "pcp_uncancel");
1377 		exit(1);
1378 	}
1379 	pcp_close(pcp);
1380 }
1381 
1382 /* Initialize */
1383 
init(const char * shell)1384 static void init(const char *shell)
1385 {
1386 	struct passwd *pw=do_getpw();
1387 
1388 	if (chdir(pw->pw_dir))
1389 	{
1390 		perror(pw->pw_dir);
1391 		exit(1);
1392 	}
1393 	unlink(".pcplogin");
1394 }
1395 
1396 /* Login to a server */
1397 
login(const char * userid)1398 static void login(const char *userid)
1399 {
1400 	char *errmsg;
1401 	char password[1024];
1402 	struct PCP *pcp;
1403 	char *p;
1404 
1405 #if HAVE_TCGETATTR
1406 	struct termios tios;
1407 	int tios_rc=tcgetattr(0, &tios);
1408 
1409 	if (tios_rc >= 0)
1410 	{
1411 		tios.c_lflag &= ~ECHO;
1412 		tcsetattr(0, TCSANOW, &tios);
1413 	}
1414 #endif
1415 
1416 	printf(gettext("Password: "));
1417 
1418 	if (fgets(password, sizeof(password), stdin) == NULL)
1419 		password[0]=0;
1420 
1421 #if HAVE_TCGETATTR
1422 	if (tios_rc >= 0)
1423 	{
1424 		tios.c_lflag |= ECHO;
1425 		tcsetattr(0, TCSANOW, &tios);
1426 		printf("\n");
1427 	}
1428 #endif
1429 
1430 	if ((p=strchr(password, '\n')) != 0)
1431 		*p=0;
1432 
1433 	pcp=pcp_open_server(userid, password, &errmsg);
1434 
1435 	if (pcp)
1436 	{
1437 		struct passwd *pw=do_getpw();
1438 		FILE *fp;
1439 		const char *p=pcp_authtoken(pcp);
1440 
1441 		if (!p)
1442 		{
1443 			fprintf(stderr, gettext("ERROR: Unable to obtain authentication token from the server.\n"));
1444 			exit(1);
1445 		}
1446 
1447 		if (chdir(pw->pw_dir) < 0)
1448 		{
1449 			perror(pw->pw_dir);
1450 			exit(1);
1451 		}
1452 		umask(077);
1453 		fp=fopen(".pcplogin", "w");
1454 
1455 		if (!fp)
1456 		{
1457 			perror("$HOME/.pcplogin");
1458 			exit(1);
1459 		}
1460 
1461 		fprintf(fp, "%s\n%s\n", userid, p);
1462 		if (fflush(fp) < 0 || ferror(fp) || fclose(fp))
1463 		{
1464 			perror("$HOME/.pcplogin");
1465 			unlink(".pcplogin");
1466 			exit(1);
1467 		}
1468 		pcp_close(pcp);
1469 		return;
1470 	}
1471 
1472 	printf(gettext("ERROR:\n%s\n"), errmsg ? errmsg:strerror(errno));
1473 	if (errmsg)
1474 		free(errmsg);
1475 }
1476 
1477 /* setacl */
1478 
setacl(const char * who,int flags)1479 static void setacl(const char *who, int flags)
1480 {
1481 	struct PCP *pcp=open_calendar();
1482 
1483 	if (pcp_has_acl(pcp))
1484 	{
1485 		if (pcp_acl(pcp, who, flags))
1486 		{
1487 			error(pcp, 0, "pcp_acl");
1488 			exit(1);
1489 		}
1490 	}
1491 	else
1492 	{
1493 		fprintf(stderr, gettext("ERROR: ACLs not supported.\n"));
1494 	}
1495 	pcp_close(pcp);
1496 }
1497 
do_list_acl(const char * who,int flags,void * dummy)1498 static int do_list_acl(const char *who, int flags, void *dummy)
1499 {
1500 	char buf[1024];
1501 
1502 	buf[0]=0;
1503 	pcp_acl_name(flags, buf);
1504 
1505 	printf("%-30s\t%s\n", who, buf);
1506 	return (0);
1507 }
1508 
listacls()1509 static void listacls()
1510 {
1511 	struct PCP *pcp=open_calendar();
1512 
1513 	if (pcp_has_acl(pcp))
1514 	{
1515 		if (pcp_list_acl(pcp, do_list_acl, NULL))
1516 		{
1517 			error(pcp, 0, "pcp_list_acl");
1518 			exit(1);
1519 		}
1520 	}
1521 	else
1522 	{
1523 		fprintf(stderr, gettext("ERROR: ACLs not supported.\n"));
1524 	}
1525 	pcp_close(pcp);
1526 }
1527 
1528 /* Connect to a PCP server */
1529 
doconnect(const char * pathname)1530 static int doconnect(const char *pathname)
1531 {
1532         int     fd=socket(PF_UNIX, SOCK_STREAM, 0);
1533         struct  sockaddr_un skun;
1534 
1535 	skun.sun_family=AF_UNIX;
1536         strcpy(skun.sun_path, pathname);
1537 
1538 	if (fd >= 0 && fcntl(fd, F_SETFL, O_NONBLOCK) >= 0)
1539 	{
1540 		if (connect(fd, (struct sockaddr *)&skun, sizeof(skun)) == 0)
1541 			return (fd);
1542 
1543 		if (errno == EINPROGRESS || errno == EWOULDBLOCK)
1544 		{
1545 			struct timeval tv;
1546 			fd_set fds;
1547 			int rc;
1548 
1549 			tv.tv_sec=10;
1550 			tv.tv_usec=0;
1551 			FD_ZERO(&fds);
1552 			FD_SET(fd, &fds);
1553 
1554 			rc=select(fd+1, NULL, &fds, NULL, &tv);
1555 
1556 			if (rc > 1 && FD_ISSET(fd, &fds))
1557 			{
1558 				if (connect(fd, (struct sockaddr *)&skun,
1559 					    sizeof(skun)) == 0)
1560 					return (fd);
1561 				if (errno == EISCONN)
1562 					return (fd);
1563 			}
1564 
1565 			if (rc >= 0)
1566 				errno=ETIMEDOUT;
1567 		}
1568 	}
1569 	perror(pathname);
1570 	exit(1);
1571 	return (0);
1572 }
1573 
1574 static void doconnectwrite(int, const char *, int);
1575 
doconnectloop(int fd)1576 static void doconnectloop(int fd)
1577 {
1578 	char buf[BUFSIZ];
1579 	fd_set rfd;
1580 
1581 	for (;;)
1582 	{
1583 		FD_ZERO(&rfd);
1584 		FD_SET(0, &rfd);
1585 		FD_SET(fd, &rfd);
1586 
1587 		if (select(fd+1, &rfd, NULL, NULL, NULL) <= 0)
1588 		{
1589 			perror("select");
1590 			continue;
1591 		}
1592 
1593 		if (FD_ISSET(fd, &rfd))
1594 		{
1595 			int n=read(fd, buf, sizeof(buf));
1596 
1597 			if (n < 0)
1598 				perror("read");
1599 			if (n <= 0)
1600 				break;
1601 			doconnectwrite(1, buf, n);
1602 		}
1603 
1604 		if (FD_ISSET(0, &rfd))
1605 		{
1606 			int n=read(0, buf, sizeof(buf));
1607 
1608 			if (n < 0)
1609 				perror("read");
1610 			if (n <= 0)
1611 				break;
1612 			doconnectwrite(fd, buf, n);
1613 		}
1614 	}
1615 	exit(0);
1616 }
1617 
doconnectwrite(int fd,const char * p,int cnt)1618 static void doconnectwrite(int fd, const char *p, int cnt)
1619 {
1620 	while (cnt > 0)
1621 	{
1622 		int n=write(fd, p, cnt);
1623 
1624 		if (n <= 0)
1625 			exit(0);
1626 
1627 		p += n;
1628 		cnt -= n;
1629 	}
1630 }
1631 
usage()1632 static void usage()
1633 {
1634 	const char *charset=RFC2045CHARSET;
1635 
1636 	{
1637 		const char *p=nl_langinfo(CODESET);
1638 
1639 		if (unicode_find(p) != NULL)
1640 			charset=p;
1641 
1642 	}
1643 
1644 
1645 	fprintf(stderr,
1646 		gettext("Usage: pcp [options] [command]\n"
1647 			"\n"
1648 			"Options:\n"
1649 			"   -c           - add/uncancel event that conflicts with an existing event\n"
1650 			"   -s subject   - specify event subject\n"
1651 			"   -C charset   - specify your local charset (default %s)\n"
1652 			"   -m           - standard input is already a MIME-formatted message\n"
1653 			"   -e           - list event ids\n"
1654 			"\n"), charset);
1655 
1656 	fprintf(stderr, "%s",
1657 		gettext(
1658 			"Commands:\n"
1659 			"   init\n"
1660 			"   login USERID\n"
1661 			"   logout\n"
1662 			"   add from FROM to TO [ from FROM to TO...]\n"
1663 			"   update ID from FROM to TO [ from FROM to TO...]\n"
1664 			"   list [all] [from FROM] [to TO] [event ID]\n"
1665 			"   cancel ID\n"
1666 			"   uncancel ID\n"
1667 			"   delete ID\n"
1668 			"   connect [/pathname]\n"
1669 			"   sconnect [/pathname]\n"
1670 			"   setacl [MODIFY|CONFLICT|LIST|RETR|NONE]*\n"
1671 			"   listacl\n"
1672 			));
1673 	exit(1);
1674 }
1675 
read_subject()1676 static char *read_subject()
1677 {
1678 	char buf[BUFSIZ];
1679 	char *p;
1680 
1681 	printf("Subject: ");
1682 
1683 	if (fgets(buf, sizeof(buf), stdin) == NULL)
1684 		exit(0);
1685 
1686 	p=strchr(buf, '\n');
1687 	if (p)
1688 		*p=0;
1689 
1690 	p=strdup(buf);
1691 
1692 	if (!p)
1693 	{
1694 		perror("malloc");
1695 		exit(1);
1696 	}
1697 	return (p);
1698 }
1699 
mimeify(const char * subject,const char * charset)1700 static char *mimeify(const char *subject, const char *charset)
1701 {
1702 	char *p=rfc2047_encode_str(subject, charset,
1703 				   rfc2047_qp_allow_any);
1704 
1705 	if (!p)
1706 	{
1707 		perror("rfc2047_encode_str");
1708 		exit(1);
1709 	}
1710 	return (p);
1711 }
1712 
main(int argc,char ** argv)1713 int main(int argc, char **argv)
1714 {
1715 	int flags=0;
1716 	int list_flags=0;
1717 	int optchar;
1718 	const char *subject=0;
1719 	int ismime=0;
1720 
1721 	setlocale(LC_ALL, "");
1722 	textdomain("pcp");
1723 
1724 	{
1725 		const char *p=nl_langinfo(CODESET);
1726 
1727 		if (unicode_find(p) != NULL)
1728 			charset=p;
1729 
1730 	}
1731 
1732 	while ((optchar=getopt(argc, argv, "emcs:C:")) >= 0)
1733 	{
1734 		switch (optchar) {
1735 		case 'c':
1736 			flags |= PCP_OK_CONFLICT;
1737 			break;
1738 		case 's':
1739 			subject=optarg;
1740 			break;
1741 		case 'C':
1742 			charset=optarg;
1743 			break;
1744 		case 'm':
1745 			ismime=1;
1746 			break;
1747 		case 'e':
1748 			list_flags |= FLAG_LIST_EVENT_ID;
1749 			break;
1750 		default:
1751 			usage();
1752 		}
1753 	}
1754 
1755 	if (optind < argc)
1756 	{
1757 		const char *addstr=gettext("add");
1758 		const char *updatestr=gettext("update");
1759 
1760 		if (strcmp(argv[optind], gettext("init")) == 0)
1761 		{
1762 			++optind;
1763 			init(optind < argc ? argv[optind]:NULL);
1764 			exit(0);
1765 		}
1766 		else if (strcmp(argv[optind], gettext("login")) == 0)
1767 		{
1768 			++optind;
1769 			if (optind < argc)
1770 			{
1771 				login(argv[optind]);
1772 				exit (0);
1773 			}
1774 		}
1775 		else if (strcmp(argv[optind], gettext("connect")) == 0)
1776 		{
1777 			int fd;
1778 			const char *n;
1779 
1780 			++optind;
1781 			n=optind < argc ? argv[optind] : PUBDIR "/50PCPDLOCAL";
1782 			fd=doconnect(n);
1783 
1784 			if (fcntl(fd, F_SETFL, 0) < 0)
1785 			{
1786 				perror(argv[optind]);
1787 				exit (0);
1788 			}
1789 			printf("Connected to %s...\n", n);
1790 			doconnectloop(fd);
1791 			exit (0);
1792 		}
1793 		else if (strcmp(argv[optind], gettext("sconnect")) == 0)
1794 		{
1795 			int fd;
1796 			const char *n;
1797 
1798 			++optind;
1799 			n=optind < argc ? argv[optind]
1800 				: PRIVDIR "/50PCPDLOCAL";
1801 			fd=doconnect(n);
1802 
1803 			if (fcntl(fd, F_SETFL, 0) < 0)
1804 			{
1805 				perror(argv[optind]);
1806 				exit (0);
1807 			}
1808 			printf("Connected to %s...\n", n);
1809 			doconnectloop(fd);
1810 			exit (0);
1811 		}
1812 		else if (strcmp(argv[optind], gettext("cancel")) == 0)
1813 		{
1814 			++optind;
1815 			if (optind < argc)
1816 			{
1817 				docancel(argv[optind], flags);
1818 				exit (0);
1819 			}
1820 		}
1821 		else if (strcmp(argv[optind], gettext("delete")) == 0)
1822 		{
1823 			++optind;
1824 			if (optind < argc)
1825 			{
1826 				dodelete(argv[optind], flags);
1827 				exit (0);
1828 			}
1829 		}
1830 		else if (strcmp(argv[optind], gettext("uncancel")) == 0)
1831 		{
1832 			++optind;
1833 			if (optind < argc)
1834 			{
1835 				douncancel(argv[optind], flags);
1836 				exit (0);
1837 			}
1838 		}
1839 		else if (strcmp(argv[optind], addstr) == 0 ||
1840 			 strcmp(argv[optind], updatestr) == 0)
1841 		{
1842 			struct add_info info;
1843 			const char *oldeventid=0;
1844 
1845 			++optind;
1846 
1847 			if (strcmp(argv[optind-1], updatestr) == 0)
1848 			{
1849 				if (optind >= argc)
1850 					usage();
1851 				oldeventid=argv[optind++];
1852 			}
1853 
1854 			memset(&info, 0, sizeof(info));
1855 
1856 			if (ismime)
1857 				info.add_func=add_read_stdin;
1858 			else
1859 			{
1860 				info.add_func=add_read_subject;
1861 				info.add_charset=charset;
1862 				if (subject)
1863 					info.add_subject=mimeify(subject,
1864 								 charset);
1865 				else
1866 				{
1867 					char *p;
1868 
1869 					if (!isatty(0))
1870 					{
1871 						fprintf(stderr,
1872 							gettext("Error: -s is required\n"));
1873 						exit(1);
1874 					}
1875 
1876 					p=read_subject();
1877 
1878 					info.add_subject=mimeify(p, charset);
1879 					free(p);
1880 				}
1881 			}
1882 			add(optind, argc, argv, flags, oldeventid, &info);
1883 			exit (0);
1884 		}
1885 		else if (strcmp(argv[optind], gettext("list")) == 0)
1886 		{
1887 			list(optind+1, argc, argv, list_flags);
1888 			exit (0);
1889 		}
1890 		else if (strcmp(argv[optind], gettext("setacl")) == 0)
1891 		{
1892 			int flags=0;
1893 			const char *acl;
1894 
1895 			if (++optind < argc)
1896 			{
1897 				acl=argv[optind];
1898 
1899 				while (++optind < argc)
1900 					flags |= pcp_acl_num(argv[optind]);
1901 
1902 				setacl(acl, flags);
1903 			}
1904 			exit (0);
1905 		}
1906 		else if (strcmp(argv[optind], gettext("listacl")) == 0)
1907 		{
1908 			listacls();
1909 			exit(0);
1910 		}
1911 	}
1912 
1913 	usage();
1914 	return (0);
1915 }
1916