Back to index

lightning-sunbird  0.9+nobinonly
stow.c
Go to the documentation of this file.
00001 /* -*- Mode: C -*-
00002   ======================================================================
00003   FILE: stow.c
00004   CREATOR: eric 29 April 2000
00005   
00006   $Id: stow.c,v 1.8 2003/11/17 22:51:53 gray-john Exp $
00007   $Locker:  $
00008     
00009  (C) COPYRIGHT 2000 Eric Busboom
00010  http://www.softwarestudio.org
00011 
00012  The contents of this file are subject to the Mozilla Public License
00013  Version 1.0 (the "License"); you may not use this file except in
00014  compliance with the License. You may obtain a copy of the License at
00015  http://www.mozilla.org/MPL/
00016  
00017  Software distributed under the License is distributed on an "AS IS"
00018  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
00019  the License for the specific language governing rights and
00020  limitations under the License.
00021  
00022  The Initial Developer of the Original Code is Eric Busboom
00023 
00024  ======================================================================*/
00025 
00026 
00027 #include <stdio.h>
00028 #include <errno.h>
00029 #include <stdio.h>
00030 #include <string.h>
00031 #include <limits.h> /* for PATH_MAX */
00032 #include <assert.h>
00033 #include <stdlib.h>
00034 #include <sys/utsname.h> /* for uname */
00035 #include <sys/stat.h> /* for stat */
00036 #include <unistd.h> /* for stat, getpid, getopt */
00037 #include <pwd.h> /* For getpwent */
00038 #include <sys/types.h> /* For getpwent */
00039 #include <ctype.h> /* for tolower */
00040 
00041 #include "ical.h"
00042 #include "icalss.h"
00043 
00044 char* program_name;
00045 #define TMPSIZE 2048
00046 #define SENDMAIL "/usr/lib/sendmail -t"
00047 
00048 void usage(char *message);
00049 
00050 #ifndef PATH_MAX
00051 #define PATH_MAX 256 /* HACK */
00052 #endif
00053 
00054 
00055 enum options {
00056     STORE_IN_FILE,
00057     STORE_IN_DB,
00058     INPUT_IS_MIME,
00059     INPUT_IS_ICAL,
00060     INPUT_FROM_STDIN,
00061     INPUT_FROM_FILE,
00062     ERRORS_TO_STDOUT,
00063     ERRORS_TO_ORGANIZER
00064 };
00065 
00066 struct options_struct
00067 {
00068        enum options storage;
00069        enum options input_type;
00070        enum options input_source;
00071        enum options errors;
00072        char* input_file;
00073        char* calid;
00074        char* output_file;
00075 };
00076 
00077 
00078 enum file_type
00079 {
00080     ERROR,
00081     NO_FILE,
00082     DIRECTORY,
00083     REGULAR,
00084     OTHER
00085 };
00086 
00087 enum file_type test_file(char *path)
00088 {
00089     struct stat sbuf;
00090     enum file_type type;
00091     
00092     errno = 0;
00093 
00094     /* Check if the path already exists and if it is a directory*/
00095     if (stat(path,&sbuf) != 0){
00096        
00097        /* A file by the given name does not exist, or there was
00098            another error */
00099        if(errno == ENOENT)
00100        {
00101            type = NO_FILE;
00102        } else {
00103            type = ERROR;
00104        }
00105 
00106     } else {
00107        /* A file by the given name exists, but is it a directory? */
00108        
00109        if (S_ISDIR(sbuf.st_mode)){ 
00110            type = DIRECTORY;
00111        } else if(S_ISREG(sbuf.st_mode)){ 
00112            type = REGULAR;
00113        } else {
00114            type = OTHER;
00115        }
00116     }
00117 
00118     return type;
00119 }
00120 
00121 char* lowercase(const char* str)
00122 {
00123     char* p = 0;
00124     char* ret;
00125 
00126     if(str ==0){
00127        return 0;
00128     }
00129 
00130     ret = strdup(str);
00131 
00132     for(p = ret; *p!=0; p++){
00133        *p = tolower(*p);
00134     }
00135 
00136     return ret;
00137 }
00138 
00139 #if 0
00140 char* get_local_attendee(struct options_struct *opt)
00141 {
00142     char attendee[PATH_MAX];
00143 
00144     if(opt->calid){
00145 
00146        strncpy(attendee,opt->calid,PATH_MAX);
00147 
00148     } else {
00149        
00150        char* user = getenv("USER");
00151        struct utsname uts;
00152        uname(&utget_option);
00153        /* HACK nodename may not be a fully qualified domain name */
00154        snprintf(attendee,PATH_MAX,"%s@%s",user,uts.nodename);
00155    
00156     }
00157 
00158     return lowercase(attendee);
00159 }
00160 #endif
00161 
00162 
00163 icalcomponent* get_first_real_component(icalcomponent *comp)
00164 {
00165     icalcomponent *c;
00166 
00167     for(c = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT);
00168        c != 0;
00169        c = icalcomponent_get_next_component(comp,ICAL_ANY_COMPONENT)){
00170        if (icalcomponent_isa(c) == ICAL_VEVENT_COMPONENT ||
00171            icalcomponent_isa(c) == ICAL_VTODO_COMPONENT ||
00172            icalcomponent_isa(c) == ICAL_VJOURNAL_COMPONENT )
00173        {
00174            return c;
00175        }
00176     }
00177 
00178     return 0;
00179 }
00180 
00181 
00182 
00183 char* make_mime(const char* to, const char* from, const char* subject, 
00184               const char* text_message, const char* method, 
00185               const char* ical_message)
00186 {
00187     size_t size = strlen(to)+strlen(from)+strlen(subject)+
00188        strlen(text_message)+ strlen(ical_message)+TMPSIZE;
00189 
00190     char mime_part_1[TMPSIZE];
00191     char mime_part_2[TMPSIZE];
00192     char content_id[TMPSIZE];
00193     char boundary[TMPSIZE];
00194     struct utsname uts;
00195     char* m;
00196 
00197 
00198     if ((m = malloc(sizeof(char)*size)) == 0){
00199        fprintf(stderr,"%s: Can't allocate memory: %s\n",program_name,strerror(errno));
00200        exit(1);
00201     }
00202 
00203     uname(&uts);
00204 
00205     srand(time(0)<<getpid());
00206     sprintf(content_id,"%d-%d@%s",(int)time(0),rand(),uts.nodename);
00207     sprintf(boundary,"%d-%d-%s",(int)time(0),rand(),uts.nodename);
00208 
00209     sprintf(mime_part_1,"Content-ID: %s\n\
00210 Content-type: text/plain\n\
00211 Content-Description: Text description of error message\n\n\
00212 %s\n\n--%s",
00213            content_id,text_message,boundary);
00214 
00215     if(ical_message != 0 && method != 0){
00216        sprintf(mime_part_2,"Content-ID: %s\n\
00217 Content-type: text/calendar; method=%s\n\
00218 Content-Description: iCal component reply\n\n\
00219 %s\n\n--%s--",
00220               content_id,method,ical_message,boundary);
00221     }
00222 
00223     sprintf(m,"To: %s\n\
00224 From: %s\n\
00225 Subject: %s\n\
00226 MIME-Version: 1.0\n\
00227 Content-ID: %s\n\
00228 Content-Type:  multipart/mixed; boundary=\"%s\"\n\
00229 \n\
00230  This is a multimedia message in MIME format\n\
00231 \n\
00232 --%s\n\
00233 %s\n\
00234 ",
00235            to,from,subject,content_id,boundary,boundary,
00236            mime_part_1);
00237 
00238     if(ical_message != 0 && method != 0){
00239        strcat(m, mime_part_2);
00240     } else {
00241        strcat(m,"--\n");
00242     }
00243 
00244     return m;
00245 }
00246 
00247 /* The incoming component had fatal errors */
00248 void return_failure(icalcomponent* comp,  char* message, 
00249                   struct options_struct *opt)
00250 {
00251     char* local_attendee = opt->calid;
00252     FILE* p;
00253     const char *org_addr;
00254 
00255     icalcomponent  *inner = get_first_real_component(comp);
00256 
00257     icalproperty *organizer_prop = icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY);
00258     const char *organizer = icalproperty_get_organizer(organizer_prop);
00259 
00260     org_addr = strchr(organizer,':');
00261 
00262     if(org_addr != 0){
00263         org_addr++; /* Skip the ';' */
00264     } else {
00265         org_addr = organizer;
00266     }
00267 
00268     if (opt->errors == ERRORS_TO_ORGANIZER){
00269        p = popen(SENDMAIL,"w");
00270     } else {
00271        p = stdout;
00272     }
00273 
00274     if(p == 0){
00275        fprintf(stderr,
00276               "%s: fatal. Could not open pipe to sendmail (\"%s\") \n",
00277               program_name,SENDMAIL);
00278        exit(1);
00279      }
00280    
00281     fputs(make_mime(org_addr, local_attendee, "iMIP error", 
00282                   message, "reply",
00283                   icalcomponent_as_ical_string(comp)),p);
00284     
00285     if (opt->errors == ERRORS_TO_ORGANIZER){ 
00286        pclose(p);
00287     }   
00288 }
00289 
00290 /* The program had a fatal error and could not process the incoming component*/
00291 void return_error(icalcomponent* comp,  char* message, struct options_struct *opt)
00292 {
00293     
00294 
00295     fputs(make_mime("Dest", "Source", "iMIP system failure", 
00296                   message, 0,0),stdout);
00297 
00298 }
00299 
00300 icalcomponent* make_reply(icalcomponent *comp, icalproperty *return_status, 
00301                       struct options_struct *opt)
00302 
00303 {
00304     icalcomponent *reply, *rinner;
00305     icalcomponent  *inner = get_first_real_component(comp);
00306     icalproperty *p=0;
00307     char* local_attendee = opt->calid;
00308     char attendee[TMPSIZE];
00309 
00310     char prodid[TMPSIZE];
00311 
00312     snprintf(attendee,TMPSIZE,"mailto:%s",local_attendee);
00313 
00314     snprintf(prodid,TMPSIZE,"-//Softwarestudio.org//%s version %s//EN",ICAL_PACKAGE,ICAL_VERSION);
00315 
00316     /* Create the base component */
00317     reply = icalcomponent_vanew( 
00318        ICAL_VCALENDAR_COMPONENT,
00319        icalproperty_new_version(strdup("2.0")),
00320        icalproperty_new_prodid(strdup(prodid)),
00321        icalproperty_new_method(ICAL_METHOD_REPLY),
00322        icalcomponent_vanew(
00323            ICAL_VEVENT_COMPONENT,
00324            icalproperty_new_clone(
00325               icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY)),
00326            icalproperty_new_clone(
00327               icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY)),
00328            icalproperty_new_clone(
00329               icalcomponent_get_first_property(inner,ICAL_UID_PROPERTY)),
00330            icalproperty_new_attendee(attendee),
00331            0),
00332        0);
00333 
00334     
00335     /* Convert errors into request-status properties and transfers
00336        them to the reply component */
00337 
00338     icalcomponent_convert_errors(comp);
00339 
00340     rinner = get_first_real_component(reply);
00341 
00342     for(p = icalcomponent_get_first_property(inner,
00343                                         ICAL_REQUESTSTATUS_PROPERTY);
00344        p != 0;
00345        p = icalcomponent_get_next_property(inner,
00346                                        ICAL_REQUESTSTATUS_PROPERTY)){
00347        
00348        icalcomponent_add_property(rinner,icalproperty_new_clone(p));
00349     }
00350               
00351     if(return_status != 0){
00352        icalcomponent_add_property(rinner, return_status);
00353     }
00354         
00355     return reply;
00356            
00357 }
00358 
00359 int check_attendee(icalproperty *p,  struct options_struct *opt){  
00360     const char* s = icalproperty_get_attendee(p);
00361     char* lower_attendee = lowercase(s);
00362     char* local_attendee = opt->calid;
00363     
00364     /* Check that attendee begins with "mailto:" */
00365     if (strncmp(lower_attendee,"mailto:",7) == 0){
00366        /* skip over the mailto: part */
00367        lower_attendee += 7;
00368        
00369        if(strcmp(lower_attendee,local_attendee) == 0){
00370            return 1;
00371        }
00372        
00373        lower_attendee -= 7;
00374        
00375        free(lower_attendee);
00376     } 
00377 
00378     return 0;
00379 }
00380 
00381 char static_component_error_str[PATH_MAX];
00382 char* check_component(icalcomponent* comp,  icalproperty **return_status,
00383                     struct options_struct *opt)
00384 {
00385     char* component_error_str=0;
00386     icalcomponent* inner;
00387     int errors = 0;
00388     icalproperty *p;
00389     int found_attendee = 0;
00390     struct icalreqstattype rs;
00391 
00392     rs.code =  ICAL_UNKNOWN_STATUS;
00393     rs.desc = 0;
00394     rs.debug = 0;
00395 
00396     /*{
00397        icalrequeststatus code;
00398        const char* desc;
00399        const char* debug;
00400         };*/
00401 
00402     *return_status = 0;
00403 
00404     /* This do/while loop only executes once because it is being used
00405        to fake exceptions */
00406 
00407     do {
00408 
00409        /* Check that we actually got a component */
00410        if(comp == 0){
00411            strcpy(static_component_error_str,
00412                  "Did not find a component");
00413            component_error_str = static_component_error_str;
00414            break;
00415        }
00416 
00417        /* Check that the root component is a VCALENDAR */
00418        if(icalcomponent_isa(comp) != ICAL_VCALENDAR_COMPONENT){
00419            strcpy(static_component_error_str,
00420                  "Root component is not a VCALENDAR");
00421            component_error_str = static_component_error_str;
00422             rs.code = ICAL_3_11_MISSREQCOMP_STATUS;
00423 
00424            break;
00425        }
00426 
00427 
00428        /* Check that the component has a METHOD */
00429 
00430        if (icalcomponent_get_first_property(comp,ICAL_METHOD_PROPERTY) == 0)
00431        {
00432            strcpy(static_component_error_str,
00433                  "The component you sent did not have a METHOD property");
00434            component_error_str = static_component_error_str;
00435             rs.code = ICAL_3_11_MISSREQCOMP_STATUS;
00436            break;
00437        }
00438        
00439        inner = get_first_real_component(comp);
00440 
00441 
00442        /* Check that the compopnent has an organizer */
00443        if(icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY) == 0){
00444            fprintf(stderr,"%s: fatal. Component does not have an ORGANIZER property\n",program_name);
00445             rs.code = ICAL_3_11_MISSREQCOMP_STATUS;
00446             break;
00447        }
00448 
00449 
00450        /* Check for this user as an attendee or organizer */
00451 
00452        for(p = icalcomponent_get_first_property(inner,ICAL_ATTENDEE_PROPERTY);
00453            p != 0;
00454            p = icalcomponent_get_next_property(inner,ICAL_ATTENDEE_PROPERTY)){
00455          
00456            found_attendee += check_attendee(p,opt);
00457        }
00458 
00459        for(p = icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY);
00460            p != 0;
00461            p = icalcomponent_get_next_property(inner,ICAL_ORGANIZER_PROPERTY)){
00462          
00463            found_attendee += check_attendee(p,opt);
00464        }
00465               
00466        if (found_attendee == 0){
00467            struct icalreqstattype rs;
00468            memset(static_component_error_str,0,PATH_MAX);
00469 
00470            snprintf(static_component_error_str,PATH_MAX,
00471                  "This target user (%s) is not listed as an attendee or organizer",
00472                   opt->calid );
00473            component_error_str = static_component_error_str;
00474 
00475            rs.code = ICAL_3_7_INVCU_STATUS;
00476 
00477            break;
00478        }
00479 
00480 
00481 
00482        /* Check that the component passes iTIP restrictions */
00483        
00484        errors = icalcomponent_count_errors(comp);
00485        icalrestriction_check(comp);
00486        
00487        if(errors != icalcomponent_count_errors(comp)){
00488            snprintf(static_component_error_str,PATH_MAX,
00489                  "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));
00490            component_error_str = static_component_error_str;
00491            break;
00492        }
00493 
00494 
00495 
00496     } while(0);
00497 
00498     if(rs.code != ICAL_UNKNOWN_STATUS){
00499         *return_status = icalproperty_new_requeststatus(rs);
00500     }
00501 
00502     return component_error_str;
00503 }
00504 
00505 
00506 void usage(char *message)
00507 {
00508     fprintf(stderr,"Usage: %s [-emdcn] [-i inputfile] [-o outputfile] [-u calid]\n",program_name);
00509     fprintf(stderr,"-e\tInput data is encapsulated in a MIME Message \n\
00510 -m\tInput is raw iCal \n\
00511 -i\tSpecify input file. Otherwise, input comes from stdin\n\
00512 -o\tSpecify file to save incoming message to\n\
00513 -d\tSpecify database to send data to\n\
00514 -u\tSet the calid to store the data to\n\
00515 -n\tSend errors to stdout instead of organizer\n\
00516 ");
00517 
00518 }
00519 
00520 
00521 void get_options(int argc, char* argv[], struct options_struct *opt)
00522 {
00523     int c;
00524     extern char *optarg;
00525     extern int optind, optopt;
00526     int errflg=0;
00527 
00528     opt->storage = STORE_IN_FILE;
00529     opt->input_source = INPUT_FROM_STDIN;
00530     opt->input_type = INPUT_IS_ICAL;
00531     opt->input_file = 0;
00532     opt->errors = ERRORS_TO_ORGANIZER;
00533     opt->calid = 0;
00534     opt->output_file = 0;
00535 
00536 
00537     while ((c = getopt(argc, argv, "nemu:o:d:b:c:i:")) != -1) {
00538              switch (c) {
00539                case 'e': { /* Input data is MIME encapsulated */
00540                    opt->input_type = INPUT_IS_MIME;
00541                    break;
00542                }
00543                case 'm': { /* Input is iCal. Default*/
00544                    opt->input_type = INPUT_IS_ICAL;
00545                    break;
00546                }
00547                case 'i': { /* Input comes from named file */
00548                    opt->input_source = INPUT_FROM_FILE;
00549                    opt->input_file = strdup(optarg);
00550                    break;
00551                }
00552                case 'o': { /* Output goes to named file. Default*/
00553                    opt->output_file = strdup(optarg);
00554                    opt->storage = STORE_IN_FILE;
00555                    break;
00556                }
00557                case 'd': { /* Output goes to database */
00558                    fprintf(stderr,"%s: option -d is unimplmented\n",program_name);
00559                    opt->storage = STORE_IN_DB;
00560                    errflg++;
00561                    break;
00562                }
00563                case 'c': {
00564 
00565                    break;
00566                }
00567                case 'u': { /* Set the calid for the output database or
00568                             file. Default is user name of user running
00569                             program */
00570                    opt->calid = strdup(optarg);
00571                    break;
00572                }
00573 
00574                case 'n': { /* Dump error to stdout. Default is to
00575                               send error to the organizer specified
00576                               in the iCal data */
00577                    opt->errors = ERRORS_TO_STDOUT;
00578                    break;
00579                }
00580 
00581                case ':': {/* Option given without an operand */
00582                    fprintf(stderr,
00583                           "%s: Option -%c requires an operand\n", 
00584                           program_name,optopt);
00585                    errflg++;
00586                    break;
00587                }
00588                case '?': {
00589                    errflg++;
00590                }
00591 
00592              }
00593 
00594             if (errflg >0){
00595                usage("");
00596                exit(1);
00597             }
00598     } 
00599 
00600     if(opt->calid == 0){
00601        /* If no calid specified, use username */
00602        char attendee[PATH_MAX];
00603        char* user = getenv("USER");
00604        struct utsname uts;
00605        uname(&uts);
00606        /* HACK nodename may not be a fully qualified domain name */
00607        snprintf(attendee,PATH_MAX,"%s@%s",user,uts.nodename);
00608 
00609        opt->calid = lowercase(attendee);
00610     }
00611 
00612     if(opt->storage == STORE_IN_FILE &&
00613        opt->output_file ==0){
00614        char file[PATH_MAX];
00615        char* user = getenv("USER");
00616        struct passwd *pw;
00617 
00618        if(!user){
00619            fprintf(stderr,"%s: Can't get username. Try explicitly specifing the output file with -o", program_name);
00620            exit(1);
00621        }
00622        
00623        /* Find password entry for user */
00624        while( (pw = getpwent())!=0){
00625            if(strcmp(user,pw->pw_name)==0){
00626               break;
00627            }
00628        }
00629            
00630        if(pw==0){
00631            fprintf(stderr,"%s: Can't get get password entry for user \"%s\" Try explicitly specifing the output file with -o", 
00632                   program_name,user);
00633            exit(1);
00634        }
00635 
00636        if(pw->pw_dir==0){
00637            fprintf(stderr,"%s: User \"%s\" has no home directory. Try explicitly specifing the output file with -o", 
00638                   program_name, user);
00639            exit(1);
00640        }
00641 
00642        snprintf(file,PATH_MAX,"%s/.facs/%s",pw->pw_dir,opt->calid);
00643 
00644        opt->output_file = strdup(file);
00645     }
00646 
00647 
00648     /* Now try to create the calendar directory if it does
00649        not exist */
00650 
00651      if(opt->storage == STORE_IN_FILE ) {
00652        char * p;
00653        char* facspath = strdup(opt->output_file);
00654        enum file_type type;
00655 
00656        /* Cut off the last slash to make it just a directoy */
00657 
00658        p = strrchr(facspath,'/');
00659 
00660         if (p != 0){
00661             /* Use some other directory */
00662             *p='\0';
00663             
00664             type = test_file(facspath);
00665             
00666             errno = 0;
00667             if (type == NO_FILE){
00668                 
00669                 if(mkdir(facspath,0775) != 0){
00670                     fprintf(stderr,
00671                             "%s: Failed to create calendar directory %s: %s\n",
00672                             program_name,facspath, strerror(errno));
00673                     exit(1);
00674                 } else {
00675                     fprintf(stderr,"%s: Creating calendar directory %s\n",
00676                             program_name,facspath);
00677                 }
00678                 
00679             } else if(type==REGULAR || type == ERROR){
00680                 fprintf(stderr,"%s: Cannot create calendar directory %s\n",
00681                         program_name,facspath);
00682                 exit(1);
00683             }                   
00684         }
00685      }
00686 }
00687 
00688 char* check_options(struct options_struct *opt)
00689 {
00690     return 0;
00691 }
00692 
00693 void store_component(icalcomponent *comp, struct options_struct *opt)
00694 {
00695     icalerrorenum error; 
00696 
00697 
00698     if(opt->storage == STORE_IN_FILE){
00699        icalset *fs = icalfileset_new(opt->output_file);
00700 
00701        if (fs == 0){
00702            fprintf(stderr,
00703                   "%s: Failed to get incoming component directory: %s\n",
00704                   program_name, icalerror_strerror(icalerrno));
00705            exit(1);
00706        }
00707 
00708 
00709        error = icalfileset_add_component(fs,comp);
00710     
00711        if (error != ICAL_NO_ERROR){
00712            fprintf(stderr,"%s: Failed to write incoming component: %s\n",
00713                   program_name, icalerror_strerror(icalerrno));
00714            exit(1);
00715        }
00716        
00717        error = icalfileset_commit(fs);
00718     
00719        if (error != ICAL_NO_ERROR){
00720            fprintf(stderr,"%s: Failed to commit incoming cluster: %s\n",
00721                   program_name, icalerror_strerror(icalerrno));
00722            exit(1);
00723        }
00724        
00725        icalset_free(fs);
00726 
00727        return;
00728     } else {
00729        assert(0);
00730     }
00731 }
00732 
00733 char* read_stream(char *s, size_t size, void *d)
00734 {
00735   char *c = fgets(s,size, (FILE*)d);
00736 
00737   return c;
00738 }
00739 
00740 icalcomponent* read_nonmime_component(struct options_struct *opt)
00741 {
00742     FILE *stream;
00743     icalcomponent *comp;
00744     icalparser* parser = icalparser_new();
00745     icalerrorstate es = icalerror_get_error_state(ICAL_MALFORMEDDATA_ERROR);
00746     char* line;
00747 
00748     if(opt->input_source == INPUT_FROM_FILE){
00749        stream = fopen(opt->input_file,"r");      
00750 
00751        if (stream == 0){
00752            perror("Can't open input file");
00753            exit(1);
00754        }
00755 
00756     } else {
00757        stream = stdin;             
00758     }
00759 
00760     assert(stream != 0);
00761     icalparser_set_gen_data(parser,stream);
00762    
00763     do {      
00764        line = icalparser_get_line(parser,read_stream);
00765        
00766         icalerror_set_error_state(ICAL_MALFORMEDDATA_ERROR,ICAL_ERROR_NONFATAL);
00767        comp = icalparser_add_line(parser,line);
00768         icalerror_set_error_state(ICAL_MALFORMEDDATA_ERROR,es);
00769        
00770        if (comp != 0){
00771            return comp;
00772        }
00773        
00774     } while ( line != 0);
00775 
00776     if(opt->input_source == INPUT_FROM_FILE){
00777        fclose(stream);
00778     }
00779 
00780 
00781     return comp;
00782  }
00783 
00784 icalcomponent* find_vcalendar(icalcomponent* comp)
00785 {
00786     icalcomponent *c,*rtrn;
00787 
00788     for(c = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT);
00789        c != 0;
00790        c = icalcomponent_get_next_component(comp,ICAL_ANY_COMPONENT)){
00791 
00792        if(icalcomponent_isa(c) == ICAL_VCALENDAR_COMPONENT){
00793            icalcomponent_remove_component(comp,c);
00794            return c;
00795        }
00796 
00797        if((rtrn=find_vcalendar(c)) != 0){
00798            return rtrn;
00799        }
00800     }
00801 
00802     return 0;
00803 }
00804 
00805 icalcomponent* read_mime_component(struct options_struct *opt)
00806 {
00807     icalcomponent *comp,*mimecomp;
00808     FILE* stream;
00809     
00810     if(opt->input_source == INPUT_FROM_FILE){
00811        stream = fopen(opt->input_file,"r");      
00812        
00813        if (stream == 0){
00814            perror("Can't open input file");
00815            exit(1);
00816        }
00817        
00818     } else {
00819        stream = stdin;             
00820     }
00821     
00822     assert(stream != 0);
00823     
00824     mimecomp = icalmime_parse(read_stream,(void*)stream);
00825 
00826     /* now find the iCal component embedded within the mime component */
00827     comp = find_vcalendar(mimecomp);
00828 
00829 
00830     if(comp == 0){
00831        return 0;
00832     }
00833 
00834     return comp;    
00835 }
00836 
00837 icalcomponent* read_component(struct options_struct *opt)
00838 {
00839     if(opt->input_type == INPUT_IS_MIME){
00840        return read_mime_component(opt);
00841     } else if (opt->input_type == INPUT_IS_ICAL){
00842        return read_nonmime_component(opt);
00843     } else {
00844        fprintf(stderr,"%s: Internal Error; unknown option for input_type\n",
00845               program_name);
00846        exit(1);
00847     }
00848 }
00849 
00850 int main(int argc, char* argv[] )
00851 {
00852     char* options_error_str;
00853     char* component_error_str;
00854     icalcomponent* comp, *reply;
00855     struct options_struct opt;
00856     icalproperty *return_status;
00857 
00858     program_name = strrchr(argv[0],'/');
00859 
00860     get_options(argc, argv, &opt);
00861 
00862     if ( (options_error_str = check_options(&opt)) != 0 ){
00863        usage(options_error_str);
00864        exit(1);
00865     }    
00866 
00867     comp = read_component(&opt);
00868 
00869     /* If the component had any fatal errors, return an error message
00870        to the organizer */
00871     if ( (component_error_str = 
00872          check_component(comp,&return_status,&opt)) != 0){
00873 
00874        reply = make_reply(comp,return_status,&opt);
00875 
00876        return_failure(reply, component_error_str, &opt);
00877        icalcomponent_free(reply);
00878        exit(0);
00879 
00880     }
00881 
00882     store_component(comp,&opt);
00883 
00884 
00885     /* Don't free the component comp, since it is now part of the
00886        store, and will be freed there */
00887 
00888     exit(0);
00889 }
00890