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