Imported Upstream version 0.48
[platform/upstream/libical.git] / src / test / stow.c
1 /* -*- Mode: C -*-
2   ======================================================================
3   FILE: stow.c
4   CREATOR: eric 29 April 2000
5   
6   $Id: stow.c,v 1.10 2008-01-02 20:07:46 dothebart Exp $
7   $Locker:  $
8     
9  (C) COPYRIGHT 2000 Eric Busboom
10  http://www.softwarestudio.org
11
12  The contents of this file are subject to the Mozilla Public License
13  Version 1.0 (the "License"); you may not use this file except in
14  compliance with the License. You may obtain a copy of the License at
15  http://www.mozilla.org/MPL/
16  
17  Software distributed under the License is distributed on an "AS IS"
18  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
19  the License for the specific language governing rights and
20  limitations under the License.
21  
22  The Initial Developer of the Original Code is Eric Busboom
23
24  ======================================================================*/
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <limits.h> /* for PATH_MAX */
35 #include <assert.h>
36 #include <stdlib.h>
37 #include <sys/utsname.h> /* for uname */
38 #include <sys/stat.h> /* for stat */
39 #if defined(HAVE_UNISTD_H)
40 #include <unistd.h> /* for stat, getpid, getopt */
41 #endif
42 #include <pwd.h> /* For getpwent */
43 #include <sys/types.h> /* For getpwent */
44 #include <ctype.h> /* for tolower */
45
46 #include <libical/ical.h>
47 #include <libicalss/icalss.h>
48
49 char* program_name;
50 #define TMPSIZE 2048
51 #define SENDMAIL "/usr/lib/sendmail -t"
52
53 void usage(char *message);
54
55 #ifndef PATH_MAX
56 #define PATH_MAX 256 /* HACK */
57 #endif
58
59
60 enum options {
61     STORE_IN_FILE,
62     STORE_IN_DB,
63     INPUT_IS_MIME,
64     INPUT_IS_ICAL,
65     INPUT_FROM_STDIN,
66     INPUT_FROM_FILE,
67     ERRORS_TO_STDOUT,
68     ERRORS_TO_ORGANIZER
69 };
70
71 struct options_struct
72 {
73         enum options storage;
74         enum options input_type;
75         enum options input_source;
76         enum options errors;
77         char* input_file;
78         char* calid;
79         char* output_file;
80 };
81
82
83 enum file_type
84 {
85     ERROR,
86     NO_FILE,
87     DIRECTORY,
88     REGULAR,
89     OTHER
90 };
91
92 enum file_type test_file(char *path)
93 {
94     struct stat sbuf;
95     enum file_type type;
96     
97     errno = 0;
98
99     /* Check if the path already exists and if it is a directory*/
100     if (stat(path,&sbuf) != 0){
101         
102         /* A file by the given name does not exist, or there was
103            another error */
104         if(errno == ENOENT)
105         {
106             type = NO_FILE;
107         } else {
108             type = ERROR;
109         }
110
111     } else {
112         /* A file by the given name exists, but is it a directory? */
113         
114         if (S_ISDIR(sbuf.st_mode)){ 
115             type = DIRECTORY;
116         } else if(S_ISREG(sbuf.st_mode)){ 
117             type = REGULAR;
118         } else {
119             type = OTHER;
120         }
121     }
122
123     return type;
124 }
125
126 char* lowercase(const char* str)
127 {
128     char* p = 0;
129     char* new = strdup(str);
130
131     if(str ==0){
132         return 0;
133     }
134
135     for(p = new; *p!=0; p++){
136         *p = tolower(*p);
137     }
138
139     return new;
140 }
141
142 #if 0
143 char* get_local_attendee(struct options_struct *opt)
144 {
145     char attendee[PATH_MAX];
146
147     if(opt->calid){
148
149         strncpy(attendee,opt->calid,PATH_MAX);
150
151     } else {
152         
153         char* user = getenv("USER");
154         struct utsname uts;
155         uname(&utget_option);
156         /* HACK nodename may not be a fully qualified domain name */
157         snprintf(attendee,PATH_MAX,"%s@%s",user,uts.nodename);
158    
159     }
160
161     return lowercase(attendee);
162 }
163 #endif
164
165
166 icalcomponent* get_first_real_component(icalcomponent *comp)
167 {
168     icalcomponent *c;
169
170     for(c = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT);
171         c != 0;
172         c = icalcomponent_get_next_component(comp,ICAL_ANY_COMPONENT)){
173         if (icalcomponent_isa(c) == ICAL_VEVENT_COMPONENT ||
174             icalcomponent_isa(c) == ICAL_VTODO_COMPONENT ||
175             icalcomponent_isa(c) == ICAL_VJOURNAL_COMPONENT )
176         {
177             return c;
178         }
179     }
180
181     return 0;
182 }
183
184
185
186 char* make_mime(const char* to, const char* from, const char* subject, 
187                 const char* text_message, const char* method, 
188                 const char* ical_message)
189 {
190     size_t size = strlen(to)+strlen(from)+strlen(subject)+
191         strlen(text_message)+ strlen(ical_message)+TMPSIZE;
192
193     char mime_part_1[TMPSIZE];
194     char mime_part_2[TMPSIZE];
195     char content_id[TMPSIZE];
196     char boundary[TMPSIZE];
197     struct utsname uts;
198     char* m;
199
200
201     if ((m = malloc(sizeof(char)*size)) == 0){
202         fprintf(stderr,"%s: Can't allocate memory: %s\n",program_name,strerror(errno));
203         exit(1);
204     }
205
206     uname(&uts);
207
208     srand(time(0)<<getpid());
209     sprintf(content_id,"%d-%d@%s",(int)time(0),rand(),uts.nodename);
210     sprintf(boundary,"%d-%d-%s",(int)time(0),rand(),uts.nodename);
211
212     sprintf(mime_part_1,"Content-ID: %s\n\
213 Content-type: text/plain\n\
214 Content-Description: Text description of error message\n\n\
215 %s\n\n--%s",
216             content_id,text_message,boundary);
217
218     if(ical_message != 0 && method != 0){
219         sprintf(mime_part_2,"Content-ID: %s\n\
220 Content-type: text/calendar; method=%s\n\
221 Content-Description: iCal component reply\n\n\
222 %s\n\n--%s--",
223                 content_id,method,ical_message,boundary);
224     }
225
226     sprintf(m,"To: %s\n\
227 From: %s\n\
228 Subject: %s\n\
229 MIME-Version: 1.0\n\
230 Content-ID: %s\n\
231 Content-Type:  multipart/mixed; boundary=\"%s\"\n\
232 \n\
233  This is a multimedia message in MIME format\n\
234 \n\
235 --%s\n\
236 %s\n\
237 ",
238             to,from,subject,content_id,boundary,boundary,
239             mime_part_1);
240
241     if(ical_message != 0 && method != 0){
242         strcat(m, mime_part_2);
243     } else {
244         strcat(m,"--\n");
245     }
246
247     return m;
248 }
249
250 /* The incoming component had fatal errors */
251 void return_failure(icalcomponent* comp,  char* message, 
252                     struct options_struct *opt)
253 {
254     char* local_attendee = opt->calid;
255     FILE* p;
256     const char *org_addr;
257
258     icalcomponent  *inner = get_first_real_component(comp);
259
260     icalproperty *organizer_prop = icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY);
261     const char *organizer = icalproperty_get_organizer(organizer_prop);
262
263     org_addr = strchr(organizer,':');
264
265     if(org_addr != 0){
266         org_addr++; /* Skip the ';' */
267     } else {
268         org_addr = organizer;
269     }
270
271     if (opt->errors == ERRORS_TO_ORGANIZER){
272         p = popen(SENDMAIL,"w");
273     } else {
274         p = stdout;
275     }
276
277     if(p == 0){
278         fprintf(stderr,
279                 "%s: fatal. Could not open pipe to sendmail (\"%s\") \n",
280                 program_name,SENDMAIL);
281         exit(1);
282      }
283    
284     fputs(make_mime(org_addr, local_attendee, "iMIP error", 
285                     message, "reply",
286                     icalcomponent_as_ical_string(comp)),p);
287     
288     if (opt->errors == ERRORS_TO_ORGANIZER){ 
289         pclose(p);
290     }   
291 }
292
293 /* The program had a fatal error and could not process the incoming component*/
294 void return_error(icalcomponent* comp,  char* message, struct options_struct *opt)
295 {
296     
297
298     fputs(make_mime("Dest", "Source", "iMIP system failure", 
299                     message, 0,0),stdout);
300
301 }
302
303 icalcomponent* make_reply(icalcomponent *comp, icalproperty *return_status, 
304                          struct options_struct *opt)
305
306 {
307     icalcomponent *reply, *rinner;
308     icalcomponent  *inner = get_first_real_component(comp);
309     icalproperty *p=0;
310     char* local_attendee = opt->calid;
311     char attendee[TMPSIZE];
312
313     char prodid[TMPSIZE];
314
315     snprintf(attendee,TMPSIZE,"mailto:%s",local_attendee);
316
317     snprintf(prodid,TMPSIZE,"-//Softwarestudio.org//%s version %s//EN",ICAL_PACKAGE,ICAL_VERSION);
318
319     /* Create the base component */
320     reply = icalcomponent_vanew( 
321         ICAL_VCALENDAR_COMPONENT,
322         icalproperty_new_version(strdup("2.0")),
323         icalproperty_new_prodid(strdup(prodid)),
324         icalproperty_new_method(ICAL_METHOD_REPLY),
325         icalcomponent_vanew(
326             ICAL_VEVENT_COMPONENT,
327             icalproperty_new_clone(
328                 icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY)),
329             icalproperty_new_clone(
330                 icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY)),
331             icalproperty_new_clone(
332                 icalcomponent_get_first_property(inner,ICAL_UID_PROPERTY)),
333             icalproperty_new_attendee(attendee),
334             0),
335         0);
336
337     
338     /* Convert errors into request-status properties and transfers
339        them to the reply component */
340
341     icalcomponent_convert_errors(comp);
342
343     rinner = get_first_real_component(reply);
344
345     for(p = icalcomponent_get_first_property(inner,
346                                              ICAL_REQUESTSTATUS_PROPERTY);
347         p != 0;
348         p = icalcomponent_get_next_property(inner,
349                                             ICAL_REQUESTSTATUS_PROPERTY)){
350         
351         icalcomponent_add_property(rinner,icalproperty_new_clone(p));
352     }
353                 
354     if(return_status != 0){
355         icalcomponent_add_property(rinner, return_status);
356     }
357         
358     return reply;
359             
360 }
361
362 int check_attendee(icalproperty *p,  struct options_struct *opt){  
363     const char* s = icalproperty_get_attendee(p);
364     char* lower_attendee = lowercase(s);
365     char* local_attendee = opt->calid;
366     
367     /* Check that attendee begins with "mailto:" */
368     if (strncmp(lower_attendee,"mailto:",7) == 0){
369         /* skip over the mailto: part */
370         lower_attendee += 7;
371         
372         if(strcmp(lower_attendee,local_attendee) == 0){
373             return 1;
374         }
375         
376         lower_attendee -= 7;
377         
378         free(lower_attendee);
379     } 
380
381     return 0;
382 }
383
384 char static_component_error_str[PATH_MAX];
385 char* check_component(icalcomponent* comp,  icalproperty **return_status,
386                       struct options_struct *opt)
387 {
388     char* component_error_str=0;
389     icalcomponent* inner;
390     int errors = 0;
391     icalproperty *p;
392     int found_attendee = 0;
393     struct icalreqstattype rs;
394
395     rs.code =  ICAL_UNKNOWN_STATUS;
396     rs.desc = 0;
397     rs.debug = 0;
398
399     /*{
400         icalrequeststatus code;
401         const char* desc;
402         const char* debug;
403         };*/
404
405     *return_status = 0;
406
407     /* This do/while loop only executes once because it is being used
408        to fake exceptions */
409
410     do {
411
412         /* Check that we actually got a component */
413         if(comp == 0){
414             strcpy(static_component_error_str,
415                    "Did not find a component");
416             component_error_str = static_component_error_str;
417             break;
418         }
419
420         /* Check that the root component is a VCALENDAR */
421         if(icalcomponent_isa(comp) != ICAL_VCALENDAR_COMPONENT){
422             strcpy(static_component_error_str,
423                    "Root component is not a VCALENDAR");
424             component_error_str = static_component_error_str;
425             rs.code = ICAL_3_11_MISSREQCOMP_STATUS;
426
427             break;
428         }
429
430
431         /* Check that the component has a METHOD */
432
433         if (icalcomponent_get_first_property(comp,ICAL_METHOD_PROPERTY) == 0)
434         {
435             strcpy(static_component_error_str,
436                    "The component you sent did not have a METHOD property");
437             component_error_str = static_component_error_str;
438             rs.code = ICAL_3_11_MISSREQCOMP_STATUS;
439             break;
440         }
441         
442         inner = get_first_real_component(comp);
443
444
445         /* Check that the compopnent has an organizer */
446         if(icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY) == 0){
447             fprintf(stderr,"%s: fatal. Component does not have an ORGANIZER property\n",program_name);
448             rs.code = ICAL_3_11_MISSREQCOMP_STATUS;
449             break;
450         }
451
452
453         /* Check for this user as an attendee or organizer */
454
455         for(p = icalcomponent_get_first_property(inner,ICAL_ATTENDEE_PROPERTY);
456             p != 0;
457             p = icalcomponent_get_next_property(inner,ICAL_ATTENDEE_PROPERTY)){
458           
459             found_attendee += check_attendee(p,opt);
460         }
461
462         for(p = icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY);
463             p != 0;
464             p = icalcomponent_get_next_property(inner,ICAL_ORGANIZER_PROPERTY)){
465           
466             found_attendee += check_attendee(p,opt);
467         }
468                 
469         if (found_attendee == 0){
470             struct icalreqstattype rs;
471             memset(static_component_error_str,0,PATH_MAX);
472
473             snprintf(static_component_error_str,PATH_MAX,
474                    "This target user (%s) is not listed as an attendee or organizer",
475                     opt->calid );
476             component_error_str = static_component_error_str;
477
478             rs.code = ICAL_3_7_INVCU_STATUS;
479
480             break;
481         }
482
483
484
485         /* Check that the component passes iTIP restrictions */
486         
487         errors = icalcomponent_count_errors(comp);
488         icalrestriction_check(comp);
489         
490         if(errors != icalcomponent_count_errors(comp)){
491             snprintf(static_component_error_str,PATH_MAX,
492                    "The component does not conform to iTIP restrictions.\n Here is the original component; look at the X-LIC-ERROR properties\nfor details\n\n%s",icalcomponent_as_ical_string(comp));
493             component_error_str = static_component_error_str;
494             break;
495         }
496
497
498
499     } while(0);
500
501     if(rs.code != ICAL_UNKNOWN_STATUS){
502         *return_status = icalproperty_new_requeststatus(rs);
503     }
504
505     return component_error_str;
506 }
507
508
509 void usage(char *message)
510 {
511     fprintf(stderr,"Usage: %s [-emdcn] [-i inputfile] [-o outputfile] [-u calid]\n",program_name);
512     fprintf(stderr,"-e\tInput data is encapsulated in a MIME Message \n\
513 -m\tInput is raw iCal \n\
514 -i\tSpecify input file. Otherwise, input comes from stdin\n\
515 -o\tSpecify file to save incoming message to\n\
516 -d\tSpecify database to send data to\n\
517 -u\tSet the calid to store the data to\n\
518 -n\tSend errors to stdout instead of organizer\n\
519 ");
520
521 }
522
523
524 void get_options(int argc, char* argv[], struct options_struct *opt)
525 {
526     int c;
527 #if !defined(HAVE_UNISTD_H)
528     extern char *optarg;
529     extern int optind, optopt;
530 #endif
531     int errflg=0;
532
533     opt->storage = STORE_IN_FILE;
534     opt->input_source = INPUT_FROM_STDIN;
535     opt->input_type = INPUT_IS_ICAL;
536     opt->input_file = 0;
537     opt->errors = ERRORS_TO_ORGANIZER;
538     opt->calid = 0;
539     opt->output_file = 0;
540
541
542     while ((c = getopt(argc, argv, "nemu:o:d:b:c:i:")) != -1) {
543              switch (c) {
544                  case 'e': { /* Input data is MIME encapsulated */
545                      opt->input_type = INPUT_IS_MIME;
546                      break;
547                  }
548                  case 'm': { /* Input is iCal. Default*/
549                      opt->input_type = INPUT_IS_ICAL;
550                      break;
551                  }
552                  case 'i': { /* Input comes from named file */
553                      opt->input_source = INPUT_FROM_FILE;
554                      opt->input_file = strdup(optarg);
555                      break;
556                  }
557                  case 'o': { /* Output goes to named file. Default*/
558                      opt->output_file = strdup(optarg);
559                      opt->storage = STORE_IN_FILE;
560                      break;
561                  }
562                  case 'd': { /* Output goes to database */
563                      fprintf(stderr,"%s: option -d is unimplmented\n",program_name);
564                      opt->storage = STORE_IN_DB;
565                      errflg++;
566                      break;
567                  }
568                  case 'c': {
569
570                      break;
571                  }
572                  case 'u': { /* Set the calid for the output database or
573                                 file. Default is user name of user running
574                                 program */
575                      opt->calid = strdup(optarg);
576                      break;
577                  }
578
579                  case 'n': { /* Dump error to stdout. Default is to
580                                 send error to the organizer specified
581                                 in the iCal data */
582                      opt->errors = ERRORS_TO_STDOUT;
583                      break;
584                  }
585
586                  case ':': {/* Option given without an operand */
587                      fprintf(stderr,
588                              "%s: Option -%c requires an operand\n", 
589                              program_name,optopt);
590                      errflg++;
591                      break;
592                  }
593                  case '?': {
594                      errflg++;
595                  }
596
597              }
598
599              if (errflg >0){
600                  usage("");
601                  exit(1);
602              }
603     } 
604
605     if(opt->calid == 0){
606         /* If no calid specified, use username */
607         char attendee[PATH_MAX];
608         char* user = getenv("USER");
609         struct utsname uts;
610         uname(&uts);
611         /* HACK nodename may not be a fully qualified domain name */
612         snprintf(attendee,PATH_MAX,"%s@%s",user,uts.nodename);
613
614         opt->calid = lowercase(attendee);
615     }
616
617     if(opt->storage == STORE_IN_FILE &&
618         opt->output_file ==0){
619         char file[PATH_MAX];
620         char* user = getenv("USER");
621         struct passwd *pw;
622
623         if(!user){
624             fprintf(stderr,"%s: Can't get username. Try explicitly specifing the output file with -o", program_name);
625             exit(1);
626         }
627         
628         /* Find password entry for user */
629         while( (pw = getpwent())!=0){
630             if(strcmp(user,pw->pw_name)==0){
631                 break;
632             }
633         }
634             
635         if(pw==0){
636             fprintf(stderr,"%s: Can't get get password entry for user \"%s\" Try explicitly specifing the output file with -o", 
637                     program_name,user);
638             exit(1);
639         }
640
641         if(pw->pw_dir==0){
642             fprintf(stderr,"%s: User \"%s\" has no home directory. Try explicitly specifing the output file with -o", 
643                     program_name, user);
644             exit(1);
645         }
646
647         snprintf(file,PATH_MAX,"%s/.facs/%s",pw->pw_dir,opt->calid);
648
649         opt->output_file = strdup(file);
650     }
651
652
653     /* Now try to create the calendar directory if it does
654        not exist */
655
656      if(opt->storage == STORE_IN_FILE ) {
657         char * p;
658         char* facspath = strdup(opt->output_file);
659         enum file_type type;
660
661         /* Cut off the last slash to make it just a directoy */
662
663         p = strrchr(facspath,'/');
664
665         if (p != 0){
666             /* Use some other directory */
667             *p='\0';
668             
669             type = test_file(facspath);
670             
671             errno = 0;
672             if (type == NO_FILE){
673                 
674                 if(mkdir(facspath,0775) != 0){
675                     fprintf(stderr,
676                             "%s: Failed to create calendar directory %s: %s\n",
677                             program_name,facspath, strerror(errno));
678                     exit(1);
679                 } else {
680                     fprintf(stderr,"%s: Creating calendar directory %s\n",
681                             program_name,facspath);
682                 }
683                 
684             } else if(type==REGULAR || type == ERROR){
685                 fprintf(stderr,"%s: Cannot create calendar directory %s\n",
686                         program_name,facspath);
687                 exit(1);
688             }               
689         }
690      }
691 }
692
693 char* check_options(struct options_struct *opt)
694 {
695     return 0;
696 }
697
698 void store_component(icalcomponent *comp, struct options_struct *opt)
699 {
700     icalerrorenum error; 
701
702
703     if(opt->storage == STORE_IN_FILE){
704         icalset *fs = icalfileset_new(opt->output_file);
705
706         if (fs == 0){
707             fprintf(stderr,
708                     "%s: Failed to get incoming component directory: %s\n",
709                     program_name, icalerror_strerror(icalerrno));
710             exit(1);
711         }
712
713
714         error = icalfileset_add_component(fs,comp);
715     
716         if (error != ICAL_NO_ERROR){
717             fprintf(stderr,"%s: Failed to write incoming component: %s\n",
718                     program_name, icalerror_strerror(icalerrno));
719             exit(1);
720         }
721         
722         error = icalfileset_commit(fs);
723     
724         if (error != ICAL_NO_ERROR){
725             fprintf(stderr,"%s: Failed to commit incoming cluster: %s\n",
726                     program_name, icalerror_strerror(icalerrno));
727             exit(1);
728         }
729         
730         icalset_free(fs);
731
732         return;
733     } else {
734         assert(0);
735     }
736 }
737
738 char* read_stream(char *s, size_t size, void *d)
739 {
740   char *c = fgets(s,size, (FILE*)d);
741
742   return c;
743 }
744
745 icalcomponent* read_nonmime_component(struct options_struct *opt)
746 {
747     FILE *stream;
748     icalcomponent *comp;
749     icalparser* parser = icalparser_new();
750     icalerrorstate es = icalerror_get_error_state(ICAL_MALFORMEDDATA_ERROR);
751     char* line;
752
753     if(opt->input_source == INPUT_FROM_FILE){
754         stream = fopen(opt->input_file,"r");    
755
756         if (stream == 0){
757             perror("Can't open input file");
758             exit(1);
759         }
760
761     } else {
762         stream = stdin;                 
763     }
764
765     assert(stream != 0);
766     icalparser_set_gen_data(parser,stream);
767    
768     do {        
769         line = icalparser_get_line(parser,read_stream);
770         
771         icalerror_set_error_state(ICAL_MALFORMEDDATA_ERROR,ICAL_ERROR_NONFATAL);
772         comp = icalparser_add_line(parser,line);
773         icalerror_set_error_state(ICAL_MALFORMEDDATA_ERROR,es);
774         
775         if (comp != 0){
776             return comp;
777         }
778         
779     } while ( line != 0);
780
781     if(opt->input_source == INPUT_FROM_FILE){
782         fclose(stream);
783     }
784
785
786     return comp;
787  }
788
789 icalcomponent* find_vcalendar(icalcomponent* comp)
790 {
791     icalcomponent *c,*rtrn;
792
793     for(c = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT);
794         c != 0;
795         c = icalcomponent_get_next_component(comp,ICAL_ANY_COMPONENT)){
796
797         if(icalcomponent_isa(c) == ICAL_VCALENDAR_COMPONENT){
798             icalcomponent_remove_component(comp,c);
799             return c;
800         }
801
802         if((rtrn=find_vcalendar(c)) != 0){
803             return rtrn;
804         }
805     }
806
807     return 0;
808 }
809
810 icalcomponent* read_mime_component(struct options_struct *opt)
811 {
812     icalcomponent *comp,*mimecomp;
813     FILE* stream;
814     
815     if(opt->input_source == INPUT_FROM_FILE){
816         stream = fopen(opt->input_file,"r");    
817         
818         if (stream == 0){
819             perror("Can't open input file");
820             exit(1);
821         }
822         
823     } else {
824         stream = stdin;                 
825     }
826     
827     assert(stream != 0);
828     
829     mimecomp = icalmime_parse(read_stream,(void*)stream);
830
831     /* now find the iCal component embedded within the mime component */
832     comp = find_vcalendar(mimecomp);
833
834
835     if(comp == 0){
836         return 0;
837     }
838
839     return comp;    
840 }
841
842 icalcomponent* read_component(struct options_struct *opt)
843 {
844     if(opt->input_type == INPUT_IS_MIME){
845         return read_mime_component(opt);
846     } else if (opt->input_type == INPUT_IS_ICAL){
847         return read_nonmime_component(opt);
848     } else {
849         fprintf(stderr,"%s: Internal Error; unknown option for input_type\n",
850                 program_name);
851         exit(1);
852     }
853 }
854
855 int main(int argc, char* argv[] )
856 {
857     char* options_error_str;
858     char* component_error_str;
859     icalcomponent* comp, *reply;
860     struct options_struct opt;
861     icalproperty *return_status;
862
863     program_name = strrchr(argv[0],'/');
864
865     get_options(argc, argv, &opt);
866
867     if ( (options_error_str = check_options(&opt)) != 0 ){
868         usage(options_error_str);
869         exit(1);
870     }    
871
872     comp = read_component(&opt);
873
874     /* If the component had any fatal errors, return an error message
875        to the organizer */
876     if ( (component_error_str = 
877           check_component(comp,&return_status,&opt)) != 0){
878
879         reply = make_reply(comp,return_status,&opt);
880
881         return_failure(reply, component_error_str, &opt);
882         icalcomponent_free(reply);
883         exit(0);
884
885     }
886
887     store_component(comp,&opt);
888
889
890     /* Don't free the component comp, since it is now part of the
891        store, and will be freed there */
892
893     exit(0);
894 }
895