Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Enumerations | Functions | Variables
stow.c File Reference
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <sys/types.h>
#include <ctype.h>
#include "ical.h"
#include "icalss.h"

Go to the source code of this file.

Classes

struct  options_struct

Defines

#define TMPSIZE   2048
#define SENDMAIL   "/usr/lib/sendmail -t"
#define PATH_MAX   256 /* HACK */

Enumerations

enum  options {
  STORE_IN_FILE, STORE_IN_DB, INPUT_IS_MIME, INPUT_IS_ICAL,
  INPUT_FROM_STDIN, INPUT_FROM_FILE, ERRORS_TO_STDOUT, ERRORS_TO_ORGANIZER
}
enum  file_type {
  ERROR, NO_FILE, DIRECTORY, REGULAR,
  OTHER
}

Functions

void usage (char *message)
enum file_type test_file (char *path)
char * lowercase (const char *str)
icalcomponent * get_first_real_component (icalcomponent *comp)
char * make_mime (const char *to, const char *from, const char *subject, const char *text_message, const char *method, const char *ical_message)
void return_failure (icalcomponent *comp, char *message, struct options_struct *opt)
void return_error (icalcomponent *comp, char *message, struct options_struct *opt)
icalcomponent * make_reply (icalcomponent *comp, icalproperty *return_status, struct options_struct *opt)
int check_attendee (icalproperty *p, struct options_struct *opt)
char * check_component (icalcomponent *comp, icalproperty **return_status, struct options_struct *opt)
void get_options (int argc, char *argv[], struct options_struct *opt)
char * check_options (struct options_struct *opt)
void store_component (icalcomponent *comp, struct options_struct *opt)
char * read_stream (char *s, size_t size, void *d)
icalcomponent * read_nonmime_component (struct options_struct *opt)
icalcomponent * find_vcalendar (icalcomponent *comp)
icalcomponent * read_mime_component (struct options_struct *opt)
icalcomponent * read_component (struct options_struct *opt)
int main (int argc, char *argv[])

Variables

char * program_name
char static_component_error_str [PATH_MAX]

Class Documentation

struct options_struct

Definition at line 66 of file stow.c.


Define Documentation

#define PATH_MAX   256 /* HACK */

Definition at line 51 of file stow.c.

#define SENDMAIL   "/usr/lib/sendmail -t"

Definition at line 46 of file stow.c.

#define TMPSIZE   2048

Definition at line 45 of file stow.c.


Enumeration Type Documentation

enum file_type
Enumerator:
ERROR 
NO_FILE 
DIRECTORY 
REGULAR 
OTHER 

Definition at line 78 of file stow.c.

Enumerator:
STORE_IN_FILE 
STORE_IN_DB 
INPUT_IS_MIME 
INPUT_IS_ICAL 
INPUT_FROM_STDIN 
INPUT_FROM_FILE 
ERRORS_TO_STDOUT 
ERRORS_TO_ORGANIZER 

Definition at line 55 of file stow.c.


Function Documentation

int check_attendee ( icalproperty *  p,
struct options_struct opt 
)

Definition at line 359 of file stow.c.

                                                                {  
    const 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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* check_component ( icalcomponent *  comp,
icalproperty **  return_status,
struct options_struct opt 
)

Definition at line 382 of file stow.c.

{
    char* component_error_str=0;
    icalcomponent* inner;
    int errors = 0;
    icalproperty *p;
    int found_attendee = 0;
    struct icalreqstattype rs;

    rs.code =  ICAL_UNKNOWN_STATUS;
    rs.desc = 0;
    rs.debug = 0;

    /*{
       icalrequeststatus code;
       const char* desc;
       const char* debug;
        };*/

    *return_status = 0;

    /* This do/while loop only executes once because it is being used
       to fake exceptions */

    do {

       /* Check that we actually got a component */
       if(comp == 0){
           strcpy(static_component_error_str,
                 "Did not find a component");
           component_error_str = static_component_error_str;
           break;
       }

       /* Check that the root component is a VCALENDAR */
       if(icalcomponent_isa(comp) != ICAL_VCALENDAR_COMPONENT){
           strcpy(static_component_error_str,
                 "Root component is not a VCALENDAR");
           component_error_str = static_component_error_str;
            rs.code = ICAL_3_11_MISSREQCOMP_STATUS;

           break;
       }


       /* Check that the component has a METHOD */

       if (icalcomponent_get_first_property(comp,ICAL_METHOD_PROPERTY) == 0)
       {
           strcpy(static_component_error_str,
                 "The component you sent did not have a METHOD property");
           component_error_str = static_component_error_str;
            rs.code = ICAL_3_11_MISSREQCOMP_STATUS;
           break;
       }
       
       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);
            rs.code = ICAL_3_11_MISSREQCOMP_STATUS;
            break;
       }


       /* 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)){
         
           found_attendee += check_attendee(p,opt);
       }

       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){
           struct icalreqstattype rs;
           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 or organizer",
                  opt->calid );
           component_error_str = static_component_error_str;

           rs.code = ICAL_3_7_INVCU_STATUS;

           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);

    if(rs.code != ICAL_UNKNOWN_STATUS){
        *return_status = icalproperty_new_requeststatus(rs);
    }

    return component_error_str;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* check_options ( struct options_struct opt)

Definition at line 688 of file stow.c.

{
    return 0;
}

Here is the caller graph for this function:

icalcomponent* find_vcalendar ( icalcomponent *  comp)

Definition at line 784 of file stow.c.

{
    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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

icalcomponent* get_first_real_component ( icalcomponent *  comp)

Definition at line 163 of file stow.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void get_options ( int  argc,
char *  argv[],
struct options_struct opt 
)

Definition at line 521 of file stow.c.

{
    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->errors = ERRORS_TO_ORGANIZER;
    opt->calid = 0;
    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(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);

       opt->calid = lowercase(attendee);
    }

    if(opt->storage == STORE_IN_FILE &&
       opt->output_file ==0){
       char file[PATH_MAX];
       char* user = getenv("USER");
       struct passwd *pw;

       if(!user){
           fprintf(stderr,"%s: Can't get username. Try explicitly specifing the output file with -o", program_name);
           exit(1);
       }
       
       /* 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);
       }

       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);
    }


    /* Now try to create the calendar directory if it does
       not exist */

     if(opt->storage == STORE_IN_FILE ) {
       char * p;
       char* facspath = strdup(opt->output_file);
       enum file_type type;

       /* Cut off the last slash to make it just a directoy */

       p = strrchr(facspath,'/');

        if (p != 0){
            /* Use some other directory */
            *p='\0';
            
            type = test_file(facspath);
            
            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);
            }                   
        }
     }
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* lowercase ( const char *  str)

Definition at line 121 of file stow.c.

{
    char* p = 0;
    char* ret;

    if(str ==0){
       return 0;
    }

    ret = strdup(str);

    for(p = ret; *p!=0; p++){
       *p = tolower(*p);
    }

    return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int main ( int  argc,
char *  argv[] 
)

Definition at line 850 of file stow.c.

{
    char* options_error_str;
    char* component_error_str;
    icalcomponent* comp, *reply;
    struct options_struct opt;
    icalproperty *return_status;

    program_name = strrchr(argv[0],'/');

    get_options(argc, argv, &opt);

    if ( (options_error_str = check_options(&opt)) != 0 ){
       usage(options_error_str);
       exit(1);
    }    

    comp = read_component(&opt);

    /* If the component had any fatal errors, return an error message
       to the organizer */
    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);

    }

    store_component(comp,&opt);


    /* Don't free the component comp, since it is now part of the
       store, and will be freed there */

    exit(0);
}

Here is the call graph for this function:

char* make_mime ( const char *  to,
const char *  from,
const char *  subject,
const char *  text_message,
const char *  method,
const char *  ical_message 
)

Definition at line 183 of file stow.c.

{
    size_t size = strlen(to)+strlen(from)+strlen(subject)+
       strlen(text_message)+ strlen(ical_message)+TMPSIZE;

    char mime_part_1[TMPSIZE];
    char mime_part_2[TMPSIZE];
    char content_id[TMPSIZE];
    char boundary[TMPSIZE];
    struct utsname uts;
    char* m;


    if ((m = malloc(sizeof(char)*size)) == 0){
       fprintf(stderr,"%s: Can't allocate memory: %s\n",program_name,strerror(errno));
       exit(1);
    }

    uname(&uts);

    srand(time(0)<<getpid());
    sprintf(content_id,"%d-%d@%s",(int)time(0),rand(),uts.nodename);
    sprintf(boundary,"%d-%d-%s",(int)time(0),rand(),uts.nodename);

    sprintf(mime_part_1,"Content-ID: %s\n\
Content-type: text/plain\n\
Content-Description: Text description of error message\n\n\
%s\n\n--%s",
           content_id,text_message,boundary);

    if(ical_message != 0 && method != 0){
       sprintf(mime_part_2,"Content-ID: %s\n\
Content-type: text/calendar; method=%s\n\
Content-Description: iCal component reply\n\n\
%s\n\n--%s--",
              content_id,method,ical_message,boundary);
    }

    sprintf(m,"To: %s\n\
From: %s\n\
Subject: %s\n\
MIME-Version: 1.0\n\
Content-ID: %s\n\
Content-Type:  multipart/mixed; boundary=\"%s\"\n\
\n\
 This is a multimedia message in MIME format\n\
\n\
--%s\n\
%s\n\
",
           to,from,subject,content_id,boundary,boundary,
           mime_part_1);

    if(ical_message != 0 && method != 0){
       strcat(m, mime_part_2);
    } else {
       strcat(m,"--\n");
    }

    return m;
}

Here is the call graph for this function:

Here is the caller graph for this function:

icalcomponent* make_reply ( icalcomponent *  comp,
icalproperty *  return_status,
struct options_struct opt 
)

Definition at line 300 of file stow.c.

{
    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;
           
}

Here is the call graph for this function:

Here is the caller graph for this function:

icalcomponent* read_component ( struct options_struct opt)

Definition at line 837 of file stow.c.

{
    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);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

icalcomponent* read_mime_component ( struct options_struct opt)

Definition at line 805 of file stow.c.

{
    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;    
}

Here is the call graph for this function:

Here is the caller graph for this function:

icalcomponent* read_nonmime_component ( struct options_struct opt)

Definition at line 740 of file stow.c.

{
    FILE *stream;
    icalcomponent *comp;
    icalparser* parser = icalparser_new();
    icalerrorstate es = icalerror_get_error_state(ICAL_MALFORMEDDATA_ERROR);
    char* line;

    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);
    icalparser_set_gen_data(parser,stream);
   
    do {      
       line = icalparser_get_line(parser,read_stream);
       
        icalerror_set_error_state(ICAL_MALFORMEDDATA_ERROR,ICAL_ERROR_NONFATAL);
       comp = icalparser_add_line(parser,line);
        icalerror_set_error_state(ICAL_MALFORMEDDATA_ERROR,es);
       
       if (comp != 0){
           return comp;
       }
       
    } while ( line != 0);

    if(opt->input_source == INPUT_FROM_FILE){
       fclose(stream);
    }


    return comp;
 }

Here is the call graph for this function:

Here is the caller graph for this function:

char* read_stream ( char *  s,
size_t  size,
void d 
)

Definition at line 733 of file stow.c.

{
  char *c = fgets(s,size, (FILE*)d);

  return c;
}

Here is the call graph for this function:

void return_error ( icalcomponent *  comp,
char *  message,
struct options_struct opt 
)

Definition at line 291 of file stow.c.

{
    

    fputs(make_mime("Dest", "Source", "iMIP system failure", 
                  message, 0,0),stdout);

}

Here is the call graph for this function:

void return_failure ( icalcomponent *  comp,
char *  message,
struct options_struct opt 
)

Definition at line 248 of file stow.c.

{
    char* local_attendee = opt->calid;
    FILE* p;
    const char *org_addr;

    icalcomponent  *inner = get_first_real_component(comp);

    icalproperty *organizer_prop = icalcomponent_get_first_property(inner,ICAL_ORGANIZER_PROPERTY);
    const char *organizer = icalproperty_get_organizer(organizer_prop);

    org_addr = strchr(organizer,':');

    if(org_addr != 0){
        org_addr++; /* Skip the ';' */
    } else {
        org_addr = organizer;
    }

    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(org_addr, local_attendee, "iMIP error", 
                  message, "reply",
                  icalcomponent_as_ical_string(comp)),p);
    
    if (opt->errors == ERRORS_TO_ORGANIZER){ 
       pclose(p);
    }   
}

Here is the call graph for this function:

Here is the caller graph for this function:

void store_component ( icalcomponent *  comp,
struct options_struct opt 
)

Definition at line 693 of file stow.c.

{
    icalerrorenum error; 


    if(opt->storage == STORE_IN_FILE){
       icalset *fs = icalfileset_new(opt->output_file);

       if (fs == 0){
           fprintf(stderr,
                  "%s: Failed to get incoming component directory: %s\n",
                  program_name, icalerror_strerror(icalerrno));
           exit(1);
       }


       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);
       }
       
       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);
       }
       
       icalset_free(fs);

       return;
    } else {
       assert(0);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

enum file_type test_file ( char *  path)

Definition at line 87 of file stow.c.

{
    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;
}

Here is the caller graph for this function:

void usage ( char *  message)

Variable Documentation

char* program_name

Definition at line 44 of file stow.c.

Definition at line 381 of file stow.c.