From 73a6d43a66a828b09e2c1b5a483405e6e0b5fa6a Mon Sep 17 00:00:00 2001 From: JP Rosevear Date: Thu, 24 Aug 2000 20:12:06 +0000 Subject: Fix minor conflicts. svn path=/trunk/; revision=5017 --- libical/src/test/stow.c | 708 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 512 insertions(+), 196 deletions(-) (limited to 'libical/src/test/stow.c') diff --git a/libical/src/test/stow.c b/libical/src/test/stow.c index d7629855c5..f742b417a5 100644 --- a/libical/src/test/stow.c +++ b/libical/src/test/stow.c @@ -33,35 +33,85 @@ #include #include /* for uname */ #include /* for stat */ -#include /* for stat, getpid */ +#include /* for stat, getpid, getopt */ +#include /* For getpwent */ +#include /* For getpwent */ +#include /* for tolower */ #include "ical.h" #include "icalcalendar.h" - +#include "icalfileset.h" +#include "icalmime.h" char* program_name; #define TMPSIZE 2048 +#define SENDMAIL "/usr/lib/sendmail -t" enum options { - STORE_IN_DIR, + STORE_IN_FILE, STORE_IN_DB, - INPUT_IS_EMAIL, + INPUT_IS_MIME, INPUT_IS_ICAL, INPUT_FROM_STDIN, - INPUT_FROM_FILE + INPUT_FROM_FILE, + ERRORS_TO_STDOUT, + ERRORS_TO_ORGANIZER }; struct options_struct { enum options storage; enum options input_type; + enum options input_source; + enum options errors; char* input_file; - char* input_text; char* calid; - char* caldir; + char* output_file; +}; + + +enum file_type +{ + ERROR, + NO_FILE, + DIRECTORY, + REGULAR, + OTHER }; +enum file_type test_file(char *path) +{ + struct stat sbuf; + enum file_type type; + + errno = 0; + + /* Check if the path already exists and if it is a directory*/ + if (stat(path,&sbuf) != 0){ + + /* A file by the given name does not exist, or there was + another error */ + if(errno == ENOENT) + { + type = NO_FILE; + } else { + type = ERROR; + } + + } else { + /* A file by the given name exists, but is it a directory? */ + + if (S_ISDIR(sbuf.st_mode)){ + type = DIRECTORY; + } else if(S_ISREG(sbuf.st_mode)){ + type = REGULAR; + } else { + type = OTHER; + } + } + return type; +} char* lowercase(char* str) { @@ -79,23 +129,33 @@ char* lowercase(char* str) return new; } +#if 0 char* get_local_attendee(struct options_struct *opt) { char attendee[PATH_MAX]; - char* user = getenv("USER"); - struct utsname uts; + if(opt->calid){ - uname(&uts); + strncpy(attendee,opt->calid,PATH_MAX); - /* HACK nodename may not be a fully qualified domain name */ - snprintf(attendee,PATH_MAX,"%s@%s",user,uts.nodename); + } else { + + char* user = getenv("USER"); + struct utsname uts; + uname(&utget_option); + /* HACK nodename may not be a fully qualified domain name */ + snprintf(attendee,PATH_MAX,"%s@%s",user,uts.nodename); + } + return lowercase(attendee); } +#endif void usage(char *message) { + fprintf(stderr,"Usage: %s [-emdcn] [-i inputfile] [-o outputfile] [-u calid]\n",program_name); + } icalcomponent* get_first_real_component(icalcomponent *comp) @@ -140,20 +200,20 @@ char* make_mime(char* to, char* from, char* subject, uname(&uts); srand(time(0)<calid; + FILE* p; - fputs(make_mime("Dest", "Source", "iMIP error", - message, "reply", - icalcomponent_as_ical_string(comp)),stdout); + icalcomponent *inner = get_first_real_component(comp); + + icalproperty *organizer_prop = icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY); + char *organizer = icalproperty_get_organizer(organizer_prop); + + organizer += 7; + if (opt->errors == ERRORS_TO_ORGANIZER){ + p = popen(SENDMAIL,"w"); + } else { + p = stdout; + } + + if(p == 0){ + fprintf(stderr, + "%s: fatal. Could not open pipe to sendmail (\"%s\") \n", + program_name,SENDMAIL); + exit(1); + } + + fputs(make_mime(organizer, local_attendee, "iMIP error", + message, "reply", + icalcomponent_as_ical_string(comp)),p); + + if (opt->errors == ERRORS_TO_ORGANIZER){ + pclose(p); + } } /* The program had a fatal error and could not process the incoming component*/ @@ -201,43 +287,124 @@ void return_error(icalcomponent* comp, char* message, struct options_struct *op } -char* check_component(icalcomponent* comp, struct options_struct *opt) +icalcomponent* make_reply(icalcomponent *comp, icalproperty *return_status, + struct options_struct *opt) + +{ + icalcomponent *reply, *rinner; + icalcomponent *inner = get_first_real_component(comp); + icalproperty *p=0; + char* local_attendee = opt->calid; + char attendee[TMPSIZE]; + + char prodid[TMPSIZE]; + + snprintf(attendee,TMPSIZE,"mailto:%s",local_attendee); + + snprintf(prodid,TMPSIZE,"-//Softwarestudio.org//%s version %s//EN",ICAL_PACKAGE,ICAL_VERSION); + + /* Create the base component */ + reply = icalcomponent_vanew( + ICAL_VCALENDAR_COMPONENT, + icalproperty_new_version(strdup("2.0")), + icalproperty_new_prodid(strdup(prodid)), + icalproperty_new_method(ICAL_METHOD_REPLY), + icalcomponent_vanew( + ICAL_VEVENT_COMPONENT, + icalproperty_new_clone( + icalcomponent_get_first_property(inner,ICAL_DTSTAMP_PROPERTY)), + icalproperty_new_clone( + icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY)), + icalproperty_new_clone( + icalcomponent_get_first_property(inner,ICAL_UID_PROPERTY)), + icalproperty_new_attendee(attendee), + 0), + 0); + + + /* Convert errors into request-status properties and transfers + them to the reply component */ + + icalcomponent_convert_errors(comp); + + rinner = get_first_real_component(reply); + + for(p = icalcomponent_get_first_property(inner, + ICAL_REQUESTSTATUS_PROPERTY); + p != 0; + p = icalcomponent_get_next_property(inner, + ICAL_REQUESTSTATUS_PROPERTY)){ + + icalcomponent_add_property(rinner,icalproperty_new_clone(p)); + } + + if(return_status != 0){ + icalcomponent_add_property(rinner, return_status); + } + + return reply; + +} + +int check_attendee(icalproperty *p, struct options_struct *opt){ + char* s = icalproperty_get_attendee(p); + char* lower_attendee = lowercase(s); + char* local_attendee = opt->calid; + + /* Check that attendee begins with "mailto:" */ + if (strncmp(lower_attendee,"mailto:",7) == 0){ + /* skip over the mailto: part */ + lower_attendee += 7; + + if(strcmp(lower_attendee,local_attendee) == 0){ + return 1; + } + + lower_attendee -= 7; + + free(lower_attendee); + } + + return 0; +} + +char static_component_error_str[PATH_MAX]; +char* check_component(icalcomponent* comp, icalproperty **return_status, + struct options_struct *opt) { - static char static_component_error_str[PATH_MAX]; char* component_error_str=0; icalcomponent* inner; int errors = 0; icalproperty *p; int found_attendee = 0; + *return_status = 0; + /* This do/while loop only executes once because it is being used to fake exceptions */ do { - /* Check that the root component is a VCALENDAR */ - if(icalcomponent_isa(comp) != ICAL_VCALENDAR_COMPONENT){ + /* Check that we actually got a component */ + if(comp == 0){ strcpy(static_component_error_str, - "Root component is not a VCALENDAR"); + "Did not find a component"); component_error_str = static_component_error_str; break; } - /* Check that the component passes iTIP restrictions */ - - errors = icalcomponent_count_errors(comp); - icalrestriction_check(comp); - - if(errors != icalcomponent_count_errors(comp)){ + /* Check that the root component is a VCALENDAR */ + if(icalcomponent_isa(comp) != ICAL_VCALENDAR_COMPONENT){ strcpy(static_component_error_str, - "The component does not conform to iTIP restrictions"); + "Root component is not a VCALENDAR"); component_error_str = static_component_error_str; break; } + /* Check that the component has a METHOD */ - if (!icalcomponent_get_first_property(comp,ICAL_METHOD_PROPERTY) == 0) + if (icalcomponent_get_first_property(comp,ICAL_METHOD_PROPERTY) == 0) { strcpy(static_component_error_str, "Component does not have a METHOD property"); @@ -245,208 +412,288 @@ char* check_component(icalcomponent* comp, struct options_struct *opt) break; } - /* Check for this user as an attendee */ + inner = get_first_real_component(comp); - inner = get_first_real_component(comp); + /* Check that the compopnent has an organizer */ + if(icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY) == 0){ + fprintf(stderr,"%s: fatal. Component does not have an ORGANIZER property\n",program_name); + + exit(1); + } + + + /* Check for this user as an attendee or organizer */ for(p = icalcomponent_get_first_property(inner,ICAL_ATTENDEE_PROPERTY); p != 0; p = icalcomponent_get_next_property(inner,ICAL_ATTENDEE_PROPERTY)){ - - char* s = icalproperty_get_attendee(p); - char* lower_attendee = lowercase(s); - char* local_attendee = get_local_attendee(opt); - - /* Check that attendee begins with "mailto:" */ - if (strncmp(lower_attendee,"mailto:",7) == 0){ - /* skip over the mailto: part */ - lower_attendee += 7; - - if(strcmp(lower_attendee,local_attendee) == 0){ - found_attendee = 1; - } - - lower_attendee -= 7; + + found_attendee += check_attendee(p,opt); + } - free(local_attendee); - free(lower_attendee); - - } + for(p = icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY); + p != 0; + p = icalcomponent_get_next_property(inner,ICAL_ORGANIZER_PROPERTY)){ + + found_attendee += check_attendee(p,opt); } - + if (found_attendee == 0){ - char* local_attendee = get_local_attendee(opt); + struct icalreqstattype rs; + char* rs_string; + memset(static_component_error_str,0,PATH_MAX); + snprintf(static_component_error_str,PATH_MAX, - "This target user (%s) is not listed as an attendee", - local_attendee ); + "This target user (%s) is not listed as an attendee or organizer", + opt->calid ); component_error_str = static_component_error_str; - free(local_attendee); + + rs.code = ICAL_3_7_INVCU_STATUS; + rs.desc = 0; + rs.debug = component_error_str; + rs_string = icalreqstattype_as_string(rs); + + *return_status = icalproperty_new_requeststatus(rs_string); break; } + + + /* Check that the component passes iTIP restrictions */ + + errors = icalcomponent_count_errors(comp); + icalrestriction_check(comp); + + if(errors != icalcomponent_count_errors(comp)){ + snprintf(static_component_error_str,PATH_MAX, + "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)); + component_error_str = static_component_error_str; + break; + } + + + } while(0); return component_error_str; } + void get_options(int argc, char* argv[], struct options_struct *opt) { - opt->storage = STORE_IN_DIR; - opt->input_type = INPUT_FROM_STDIN; + int c; + extern char *optarg; + extern int optind, optopt; + int errflg=0; + + opt->storage = STORE_IN_FILE; + opt->input_source = INPUT_FROM_STDIN; + opt->input_type = INPUT_IS_ICAL; opt->input_file = 0; - opt->input_text = 0; + opt->errors = ERRORS_TO_ORGANIZER; opt->calid = 0; - opt->caldir = 0; -} - -char* check_options(struct options_struct *opt) -{ - return 0; -} - -void store_component(icalcomponent *comp, icalcalendar* cal, - struct options_struct *opt) -{ - - icalcluster *incoming = 0; - icalerrorenum error; - - incoming = icalcalendar_get_incoming(cal); + opt->output_file = 0; + + + while ((c = getopt(argc, argv, "nemu:o:d:b:c:i:")) != -1) { + switch (c) { + case 'e': { /* Input data is MIME encapsulated */ + opt->input_type = INPUT_IS_MIME; + break; + } + case 'm': { /* Input is iCal. Default*/ + opt->input_type = INPUT_IS_ICAL; + break; + } + case 'i': { /* Input comes from named file */ + opt->input_source = INPUT_FROM_FILE; + opt->input_file = strdup(optarg); + break; + } + case 'o': { /* Output goes to named file. Default*/ + opt->output_file = strdup(optarg); + opt->storage = STORE_IN_FILE; + break; + } + case 'd': { /* Output goes to database */ + fprintf(stderr,"%s: option -d is unimplmented\n",program_name); + opt->storage = STORE_IN_DB; + errflg++; + break; + } + case 'c': { + + break; + } + case 'u': { /* Set the calid for the output database or + file. Default is user name of user running + program */ + opt->calid = strdup(optarg); + break; + } + + case 'n': { /* Dump error to stdout. Default is to + send error to the organizer specified + in the iCal data */ + opt->errors = ERRORS_TO_STDOUT; + break; + } + + case ':': {/* Option given without an operand */ + fprintf(stderr, + "%s: Option -%c requires an operand\n", + program_name,optopt); + errflg++; + break; + } + case '?': { + errflg++; + } + + } + + if (errflg >0){ + usage(""); + exit(1); + } + } - if (incoming == 0){ - fprintf(stderr,"%s: Failed to get incoming component directory: %s\n", - program_name, icalerror_strerror(icalerrno)); - exit(1); - } + if(opt->calid == 0){ + /* If no calid specified, use username */ + char attendee[PATH_MAX]; + char* user = getenv("USER"); + struct utsname uts; + uname(&uts); + /* HACK nodename may not be a fully qualified domain name */ + snprintf(attendee,PATH_MAX,"%s@%s",user,uts.nodename); - error = icalcluster_add_component(incoming,comp); - - if (error != ICAL_NO_ERROR){ - fprintf(stderr,"%s: Failed to write incoming component: %s\n", - program_name, icalerror_strerror(icalerrno)); - exit(1); - } - - error = icalcluster_commit(incoming); - - if (error != ICAL_NO_ERROR){ - fprintf(stderr,"%s: Failed to commit incoming cluster: %s\n", - program_name, icalerror_strerror(icalerrno)); - exit(1); + opt->calid = lowercase(attendee); } - - return; -} - -enum file_type -{ - ERROR, - NO_FILE, - DIRECTORY, - REGULAR, - OTHER -}; -enum file_type test_file(char *path) -{ - struct stat sbuf; - enum file_type type; - - errno = 0; + if(opt->storage == STORE_IN_FILE && + opt->output_file ==0){ + char file[PATH_MAX]; + char* user = getenv("USER"); + struct passwd *pw; - /* Check if the path already exists and if it is a directory*/ - if (stat(path,&sbuf) != 0){ + if(!user){ + fprintf(stderr,"%s: Can't get username. Try explicitly specifing the output file with -o", program_name); + exit(1); + } - /* A file by the given name does not exist, or there was - another error */ - if(errno == ENOENT) - { - type = NO_FILE; - } else { - type = ERROR; + /* Find password entry for user */ + while( (pw = getpwent())!=0){ + if(strcmp(user,pw->pw_name)==0){ + break; + } + } + + if(pw==0){ + fprintf(stderr,"%s: Can't get get password entry for user \"%s\" Try explicitly specifing the output file with -o", + program_name,user); + exit(1); } - } else { - /* A file by the given name exists, but is it a directory? */ - - if (S_ISDIR(sbuf.st_mode)){ - type = DIRECTORY; - } else if(S_ISREG(sbuf.st_mode)){ - type = REGULAR; - } else { - type = OTHER; + if(pw->pw_dir==0){ + fprintf(stderr,"%s: User \"%s\" has no home directory. Try explicitly specifing the output file with -o", + program_name, user); + exit(1); } + + snprintf(file,PATH_MAX,"%s/.facs/%s",pw->pw_dir,opt->calid); + + opt->output_file = strdup(file); } - return type; -} -icalcalendar* get_calendar(icalcomponent* comp, struct options_struct *opt) -{ - - struct stat sbuf; - char calpath[PATH_MAX]; - char facspath[PATH_MAX]; - char* home = getenv("HOME"); - char* user = getenv("USER"); - enum file_type type; - icalcalendar* cal; + /* Now try to create the calendar directory if it does + not exist */ - snprintf(facspath,PATH_MAX,"%s/.facs",home); + if(opt->storage == STORE_IN_FILE ) { + char * p; + char* facspath = strdup(opt->output_file); + enum file_type type; - type = test_file(facspath); + /* Cut off the last slash to make it just a directoy */ - errno = 0; - if (type == NO_FILE){ + p = strrchr(facspath,'/'); - if(mkdir(facspath,0775) != 0){ - fprintf(stderr,"%s: Failed to create calendar store directory %s: %s\n", - program_name,facspath, strerror(errno)); - exit(1); - } else { - printf("%s: Creating calendar store directory %s\n",program_name,facspath); - } + if (p == 0){ + fprintf(stderr,"%s: Invalid calendar filename \"%s\"", + program_name,facspath); + exit(1); + } + + *p='\0'; + + type = test_file(facspath); - } else if(type==REGULAR || type == ERROR){ - fprintf(stderr,"%s: Cannot create calendar store directory %s\n", + errno = 0; + if (type == NO_FILE){ + + if(mkdir(facspath,0775) != 0){ + fprintf(stderr, + "%s: Failed to create calendar directory %s: %s\n", + program_name,facspath, strerror(errno)); + exit(1); + } else { + fprintf(stderr,"%s: Creating calendar directory %s\n", + program_name,facspath); + } + + } else if(type==REGULAR || type == ERROR){ + fprintf(stderr,"%s: Cannot create calendar directory %s\n", program_name,facspath); exit(1); - } + } + } +} +char* check_options(struct options_struct *opt) +{ + return 0; +} +void store_component(icalcomponent *comp, struct options_struct *opt) +{ + icalerrorenum error; - snprintf(calpath,PATH_MAX,"%s/%s",facspath,user); - type = test_file(calpath); + if(opt->storage == STORE_IN_FILE){ + icalfileset *fs = icalfileset_new(opt->output_file); - errno = 0; + if (fs == 0){ + fprintf(stderr, + "%s: Failed to get incoming component directory: %s\n", + program_name, icalerror_strerror(icalerrno)); + exit(1); + } - if (type == NO_FILE){ - if(mkdir(calpath,0775) != 0){ - fprintf(stderr,"%s: Failed to create calendar directory %s: %s\n", - program_name,calpath, strerror(errno)); - } else { - printf("%s: Creating calendar store directory %s\n",program_name,facspath); + error = icalfileset_add_component(fs,comp); + + if (error != ICAL_NO_ERROR){ + fprintf(stderr,"%s: Failed to write incoming component: %s\n", + program_name, icalerror_strerror(icalerrno)); + exit(1); } - } else if(type==REGULAR || type == ERROR){ - fprintf(stderr,"%s: Cannot create calendar directory %s\n", - program_name,calpath); + + error = icalfileset_commit(fs); + + if (error != ICAL_NO_ERROR){ + fprintf(stderr,"%s: Failed to commit incoming cluster: %s\n", + program_name, icalerror_strerror(icalerrno)); exit(1); - } - - cal = icalcalendar_new(calpath); + } + + icalfileset_free(fs); - if(cal == 0){ - fprintf(stderr,"%s: Failed to open calendar at %s: %s", - program_name,calpath,icalerror_strerror(icalerrno)); - exit(1); + return; + } else { + assert(0); } - - return cal; - } char* read_stream(char *s, size_t size, void *d) @@ -456,14 +703,14 @@ char* read_stream(char *s, size_t size, void *d) return c; } -icalcomponent* read_component(struct options_struct *opt) +icalcomponent* read_nonmime_component(struct options_struct *opt) { FILE *stream; icalcomponent *comp; icalparser* parser = icalparser_new(); char* line; - if(opt->input_type == INPUT_FROM_FILE){ + if(opt->input_source == INPUT_FROM_FILE){ stream = fopen(opt->input_file,"r"); if (stream == 0){ @@ -490,22 +737,89 @@ icalcomponent* read_component(struct options_struct *opt) } while ( line != 0); - if(opt->input_type == INPUT_FROM_FILE){ + if(opt->input_source == INPUT_FROM_FILE){ fclose(stream); } + return comp; } +icalcomponent* find_vcalendar(icalcomponent* comp) +{ + icalcomponent *c,*rtrn; + + for(c = icalcomponent_get_first_component(comp,ICAL_ANY_COMPONENT); + c != 0; + c = icalcomponent_get_next_component(comp,ICAL_ANY_COMPONENT)){ + + if(icalcomponent_isa(c) == ICAL_VCALENDAR_COMPONENT){ + icalcomponent_remove_component(comp,c); + return c; + } + + if((rtrn=find_vcalendar(c)) != 0){ + return rtrn; + } + } + + return 0; +} + +icalcomponent* read_mime_component(struct options_struct *opt) +{ + icalcomponent *comp,*mimecomp; + FILE* stream; + + if(opt->input_source == INPUT_FROM_FILE){ + stream = fopen(opt->input_file,"r"); + + if (stream == 0){ + perror("Can't open input file"); + exit(1); + } + + } else { + stream = stdin; + } + + assert(stream != 0); + + mimecomp = icalmime_parse(read_stream,(void*)stream); + + /* now find the iCal component embedded within the mime component */ + comp = find_vcalendar(mimecomp); + + + if(comp == 0){ + return 0; + } + + return comp; +} + +icalcomponent* read_component(struct options_struct *opt) +{ + if(opt->input_type == INPUT_IS_MIME){ + return read_mime_component(opt); + } else if (opt->input_type == INPUT_IS_ICAL){ + return read_nonmime_component(opt); + } else { + fprintf(stderr,"%s: Internal Error; unknown option for input_type\n", + program_name); + exit(1); + } +} + int main(int argc, char* argv[] ) { char* options_error_str; char* component_error_str; - icalcalendar* cal; icalcomponent* comp, *reply; struct options_struct opt; + icalproperty *return_status; - program_name = argv[0]; + program_name = strrchr(argv[0],'/'); get_options(argc, argv, &opt); @@ -516,17 +830,19 @@ int main(int argc, char* argv[] ) comp = read_component(&opt); - if ( (component_error_str = check_component(comp,&opt)) != 0){ - return_failure(comp, component_error_str, &opt); - exit(1); + if ( (component_error_str = + check_component(comp,&return_status,&opt)) != 0){ + reply = make_reply(comp,return_status,&opt); + return_failure(reply, component_error_str, &opt); + icalcomponent_free(reply); + exit(0); } - cal = get_calendar(comp,&opt); + store_component(comp,&opt); - store_component(comp,cal, &opt); - icalcomponent_free(comp); - icalcalendar_free(cal); + /* Don't free the component comp, since it is now part of the + store, and will be freed there */ exit(0); } -- cgit