Source File ep/mail_parser.c

    1    | /***************************************
    2    |   $Revision: 1.28 $
    3    |
    4    |   Email Parser module (ep) - wrapping functions to parse email,
    5    |   calling MM and PA.
    6    |
    7    |   Status: NOT REVUED, TESTED
    8    |
    9    |   ******************/ /******************
    10   |   Filename            : mail_parser.c
    11   |   Authors             : Filippo Portera, Daniele Arena
    12   |   OSs Tested          : Solaris 7
    13   |   ******************/ /******************
    14   |   Copyright (c) 2000,2001,2002                    RIPE NCC
    15   |
    16   |   All Rights Reserved
    17   |
    18   |   Permission to use, copy, modify, and distribute this software and its
    19   |   documentation for any purpose and without fee is hereby granted,
    20   |   provided that the above copyright notice appear in all copies and that
    21   |   both that copyright notice and this permission notice appear in
    22   |   supporting documentation, and that the name of the author not be
    23   |   used in advertising or publicity pertaining to distribution of the
    24   |   software without specific, written prior permission.
    25   |
    26   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
    27   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
    28   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
    29   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
    30   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    31   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    32   |   ***************************************/
    33   |
    34   | #include <stdio.h>
    35   | #include <string.h>
    36   | #include <stdlib.h>
    37   | #include <netdb.h>
    38   | #include <sys/param.h>
    39   |
    40   | #include "mm.h"
    41   | #include "gpg.h"
    42   | #include "mail_parser.h"
    43   |
    44   | /* Parse the mail message stored in inputFile and develop it
    45   |    in distinct text files, writing them on the outputPath
    46   |    directory and using the variable keyRing to read public
    47   |    keys needed for the verification process.
    48   |
    49   |    The common use of this parse should look like this:
    50   |
    51   |    p = EP_ParseMessage("mail.001", "/tmp", "~/.gnupg/pubring.gpg");
    52   |
    53   |    < parse the tree: p->tree >
    54   |
    55   |    EP_TreeCleanUp(p);
    56   |
    57   | */
    58   |
    59   | /* Globals to store shared data for tree nodes */
    60   |
    61   | char EP_outputPrefix[FILENAME_LENGTH];
    62   | char EP_keyRing[FILENAME_LENGTH];
    63   | char EP_gpgcmd[FILENAME_LENGTH];
    64   | int  EP_TreeHeight;
    65   | int  EP_Node_ID;
    66   | int  EP_Debug;
    67   |
    68   | const char *vS_strRC[] = { "IS_VALID",
    69   | 			   "IS_NOT_PGP",
    70   | 			   "KO",
    71   | 			   "CRC_ERROR",
    72   | 			   "NO_PUBLIC_KEY",
    73   | 			   "NO_OPENPGP_DATA",
    74   | 			   "NO_IN_FILES",
    75   | 			   "NO_OUT_FILES",
    76   | 			   "TO_BE_PGPVERIFIED",
    77   | 			   "UNABLE_TO_WRITE_FILE",
    78   | 			   "UNMATCHED_PGP_DELIMITERS"
    79   |                          };
    80   |
    81   | #define EP_TREEMAXHEIGHT 10;
    82   |
    83   | EP_Mail_DescrPtr InitializeMailDescr( const char *inputFile ) {
    84   |
    85   |   EP_Mail_DescrPtr ptr;
    86   |   /*  EPNodePtr rootNode; */
    87   |   int retcode;
    88   |   long debug = 0;
    89   |
    90   |   ptr = UT_malloc(sizeof(EP_Mail_Descr));
    91   |
    92   |   ptr->from = ptr->subject = ptr->date =
    93   |   ptr->message_id = ptr->reply_to = ptr->cc =
    94   |   ptr->content_type = NULL ;
    95   |
    96   |
    97   |   /* Obtain headers */
    98   |   retcode = MM_get_headers(inputFile, ptr, debug);
    99   |
    100  |   ptr->tree = EP_InitializeRootNode(inputFile);
    101  |
    102  |   return ptr;
    103  | }
    104  |
    105  | /* ------------------------------------------------- */
    106  |
    107  | EP_Mail_DescrPtr EP_ParseMail(const char *inputFile,
    108  | 			      const char *outputPath,
    109  | 			      const char *keyRing,
    110  | 			      const char *gpgcmd) {
    111  |   EP_Mail_DescrPtr ptr;
    112  |   char hostname[MAXHOSTNAMELEN];
    113  |   int retcode;
    114  |   long debug = 0;
    115  |   char mail_file[FILENAMELEN];
    116  |
    117  |   EP_Debug = debug;
    118  |
    119  |   gethostname(hostname, MAXHOSTNAMELEN);
    120  |   sprintf(EP_outputPrefix, "%s/EPMtmp.%s.%d.", outputPath,
    121  | 	  hostname, getpid());
    122  |   strcpy(EP_keyRing, keyRing);
    123  |   strcpy(EP_gpgcmd, gpgcmd);
    124  |
    125  |   sprintf (mail_file,"%sunprocessed", EP_outputPrefix);      /* the file where the mail message will be stored */
    126  |
    127  |   /* if ((retcode = MM_store((char*)inputFile,mail_file, debug)) != 0)
    128  |     exit (retcode); */
    129  |
    130  |   MM_store((char*)inputFile,mail_file, debug);
    131  |
    132  |   ptr = InitializeMailDescr(mail_file);
    133  |   /* Invoke the MIME parser */
    134  |   retcode = MM_extract_mime(mail_file, NULL, ptr->tree, debug);
    135  |
    136  |   return ptr;
    137  | }
    138  |
    139  | /* ------------------------------------------------- */
    140  |
    141  | EPNodePtr EP_ParseText(const char *inputFile,
    142  | 		       const char *outputPath,
    143  | 		       const char *keyRing,
    144  | 		       const char *gpgcmd) {
    145  |   EPNodePtr ptr;
    146  |   char hostname[MAXHOSTNAMELEN];
    147  |
    148  |   EP_Debug = 0;
    149  |
    150  |   gethostname(hostname, MAXHOSTNAMELEN);
    151  |   sprintf(EP_outputPrefix, "%s/EPTtmp.%s.%d.", outputPath,
    152  | 	  hostname, getpid());
    153  |
    154  |   strcpy(EP_keyRing, keyRing);
    155  |   strcpy(EP_gpgcmd, gpgcmd);
    156  |
    157  |   ptr = EP_InitializeRootNode(inputFile);
    158  |
    159  |   return PA_ParseMessage(ptr);
    160  | }
    161  |
    162  |
    163  | /* ------------------------------------------------- */
    164  |
    165  | EPNodePtr EP_MIMEParse(const EPNodePtr p)
    166  | {
    167  |   char mail_file[FILENAMELEN];
    168  |   int retcode;
    169  |   FILE * fin;
    170  |   char *strptr;
    171  |   int found = 0, headers_end = 0;
    172  |   char txt[MAX_LINE_BUF];
    173  |
    174  |   sprintf (mail_file,"%s%d.unprocessed", EP_outputPrefix, p->nodeID);      /* the file where the mail message will be stored */
    175  |
    176  |   /* Quest for a mail header:
    177  |      look for a mail header of type (content-type || mime version).
    178  |   */
    179  |
    180  |   if ((fin = fopen(p->file, "r")) != NULL) {
    181  |     while ( !headers_end && !found &&
    182  | 	    (strptr = fgets(txt, MAX_LINE_BUF, fin)) != NULL) {
    183  |       if ( do_regex_test("^Content-Type:", txt) ||
    184  | 	   do_regex_test("^MIME-Version:", txt)) {
    185  | 	found = 1;
    186  | 	fclose(fin);
    187  |
    188  | 	/* if ((retcode = MM_store((char*)p->file,mail_file, EP_Debug)) != 0) {
    189  | 	   fprintf(stderr, "Error on MM_Store: %d\n", retcode );
    190  | 	   } */
    191  |
    192  | 	MM_store((char*)p->file,mail_file, EP_Debug);
    193  |
    194  |  	/* Invoke the MIME parser */
    195  | 	retcode = MM_extract_mime(mail_file, NULL, p, EP_Debug);
    196  |       } else
    197  | 	if ( do_regex_test("^ *\n", txt) )
    198  | 	  headers_end = 1;
    199  |     }
    200  |
    201  |     if (!found) {
    202  |       fclose(fin);
    203  |       PA_ParseMessage(p);
    204  |     }
    205  |
    206  |   } else {
    207  |     p->isValidPGPSignature = vS_NO_IN_FILES;
    208  |   }
    209  |
    210  |   return p;
    211  | }
    212  |
    213  | /* ------------------------------------------------- */
    214  |
    215  | EPNodePtr EP_InitializeRootNode( const char *inputFile ) {
    216  |   EPNodePtr rootNode;
    217  |
    218  |   EP_TreeHeight = EP_Node_ID = 0;
    219  |
    220  |   rootNode = UT_malloc(sizeof(struct EPNode));
    221  |
    222  |   rootNode->nodeID = 0;
    223  |   rootNode->isValidPGPSignature = vS_IS_NOT_PGP;
    224  |   rootNode->keyID = 0;
    225  |   rootNode->MIMEContentType = -1;
    226  |   rootNode->strMIMEContentType = NULL;
    227  |   rootNode->file = strdup(inputFile);
    228  |   rootNode->inner = NULL;
    229  |   rootNode->next = NULL;
    230  |
    231  |   return rootNode;
    232  | }
    233  |
    234  | /* ------------------------------------------------- */
    235  |
    236  | EPNodePtr EP_InitializeNode( const char *inputFile, const int nodeID ) {
    237  |   EPNodePtr node;
    238  |
    239  |   node = UT_malloc(sizeof(struct EPNode));
    240  |
    241  |   node->nodeID = nodeID;
    242  |   node->isValidPGPSignature = vS_IS_NOT_PGP;
    243  |   node->keyID = 0;
    244  |   node->MIMEContentType = -1;
    245  |   node->strMIMEContentType = NULL;
    246  |   node->file = strdup(inputFile);
    247  |   node->inner = NULL;
    248  |   node->next = NULL;
    249  |
    250  |   return node;
    251  | }
    252  |
    253  | /* ------------------------------------------------- */
    254  |
    255  | EPNodePtr EP_DefineNewNode( const int nodeID,
    256  | 			    const short isValidPGPSignature,
    257  | 			    const t_MM_type MIMEContentType,
    258  | 			    const char *strMIMEContentType,
    259  | 			    const u32 keyID) {
    260  |   EPNodePtr node;
    261  |
    262  |   node = (EPNodePtr) UT_malloc(sizeof(EP_mail_node));
    263  |
    264  |   /*  printf("node: %d, %p\n", nodeID, node); */
    265  |
    266  |   node->nodeID = nodeID;
    267  |   node->isValidPGPSignature = isValidPGPSignature;
    268  |   node->keyID = keyID;
    269  |   node->MIMEContentType = MIMEContentType;
    270  |   node->strMIMEContentType = (strMIMEContentType == NULL ? NULL :
    271  | 			      strdup(strMIMEContentType) );
    272  |   node->inner = NULL;
    273  |   node->next = NULL;
    274  |   EP_BuildFilename(node);
    275  |
    276  |   return node;
    277  | }
    278  |
    279  | /* ------------------------------------------------- */
    280  | /* Deallocate parsing tree and remove files */
    281  |
    282  | void EP_TreeCleanUp(const EPNodePtr ptr) {
    283  |
    284  |   if (ptr->file != NULL) {
    285  |     unlink(ptr->file);
    286  |     /*    printf("node: %d, %p\n", ptr->nodeID, ptr); */
    287  |     free(ptr->file);
    288  |   }
    289  |   if (ptr->strMIMEContentType != NULL) {
    290  |     free(ptr->strMIMEContentType);
    291  |   }
    292  |
    293  |   if (ptr->inner != NULL) EP_TreeCleanUp(ptr->inner);
    294  |   if (ptr->next != NULL) EP_TreeCleanUp(ptr->next);
    295  |
    296  |   free(ptr);
    297  | }
    298  |
    299  | /* ------------------------------------------------- */
    300  | void MailHeaderFieldCleanUp(Mail_Header_FieldPtr p) {
    301  |   Mail_Header_FieldPtr ptmp = p, prev;
    302  |
    303  |   while (ptmp != NULL) {
    304  |     prev = ptmp;
    305  |     ptmp = ptmp->next;
    306  |     if (prev->field != NULL)
    307  |       free(prev->field);
    308  |     free(prev);
    309  |   }
    310  | }
    311  |
    312  |
    313  | /* ------------------------------------------------- */
    314  |
    315  | /* Deallocate parsing tree and remove files */
    316  |
    317  | void EP_MailDescrCleanUp(const EP_Mail_DescrPtr ptr) {
    318  |
    319  |   if (ptr != NULL) {
    320  |
    321  |     MailHeaderFieldCleanUp(ptr->from);
    322  |     MailHeaderFieldCleanUp(ptr->subject);
    323  |     MailHeaderFieldCleanUp(ptr->date);
    324  |     MailHeaderFieldCleanUp(ptr->message_id);
    325  |     MailHeaderFieldCleanUp(ptr->reply_to);
    326  |     MailHeaderFieldCleanUp(ptr->cc);
    327  |     MailHeaderFieldCleanUp(ptr->content_type);
    328  |
    329  |     EP_TreeCleanUp(ptr->tree);
    330  |     free(ptr);
    331  |   }
    332  | }
    333  |
    334  | /* ------------------------------------------------- */
    335  | /* Build a node filename */
    336  |
    337  | void EP_BuildFilename(const EPNodePtr ptr) {
    338  |   char file[FILENAME_LENGTH];
    339  |
    340  |   sprintf(file, "%s%d", EP_outputPrefix, ptr->nodeID);
    341  |   ptr->file = strdup(file);
    342  | }
    343  |
    344  | /* ------------------------------------------------- */
    345  |
    346  | void EP_ShowTree(const EPNodePtr p) {
    347  |   if (p != NULL) {
    348  |     /* if (EP_HasContent(p)) { */
    349  |       printf("Node ID: %d\n", p->nodeID);
    350  |       printf("isValidPGPSignature: %s\n",  vS_strRC[p->isValidPGPSignature]);
    351  |       printf("MIMEContentType: %d\n", p->MIMEContentType);
    352  |       printf("Key ID: %0X\n", p->keyID);
    353  |       printf("file: %s\n\n\n", p->file);
    354  |       /* } */
    355  |     if (p->inner != NULL)
    356  |       EP_ShowTree(p->inner);
    357  |     if (p->next != NULL)
    358  |       EP_ShowTree(p->next);
    359  |   }
    360  | }
    361  |
    362  | /* ------------------------------------------------- */
    363  |
    364  | EPTokenPtr EP_DefineNewToken( const t_MM_type MIMEContentType,
    365  | 			      const char *file,
    366  | 			      const EPTokenKeysPtr keysList ) {
    367  |   EPTokenPtr token;
    368  |   EPTokenKeysPtr head = NULL, p = keysList, pnew, prev = NULL;
    369  |
    370  |   token = (EPTokenPtr) UT_malloc(sizeof(EPToken));
    371  |   token->file = (char*)file;
    372  |   token->MIMEContentType = MIMEContentType;
    373  |
    374  |
    375  |   /* generate head, and build the key list for this result node */
    376  |   if (p != NULL) {
    377  |     pnew = (EPTokenKeysPtr) UT_malloc(sizeof(EPTokenKeys));
    378  |     pnew->isValidPGPSignature = p->isValidPGPSignature;
    379  |     pnew->keyID = p->keyID;
    380  |     pnew->next = NULL;
    381  |     head = prev = pnew;
    382  |     p = p->next;
    383  |   }
    384  |
    385  |   while (p != NULL) {
    386  |     pnew = (EPTokenKeysPtr) UT_malloc(sizeof(EPTokenKeys));
    387  |     pnew->isValidPGPSignature = p->isValidPGPSignature;
    388  |     pnew->keyID = p->keyID;
    389  |     pnew->next = NULL;
    390  |     prev->next = pnew;
    391  |     prev = pnew;
    392  |     p = p->next;
    393  |   }
    394  |
    395  |   token->keys = head;
    396  |   token->next = token->prev = NULL;
    397  |
    398  |   return token;
    399  | }
    400  |
    401  | /* ------------------------------------------------- */
    402  |
    403  | EPTokenKeysPtr AddKeyInfo( EPTokenKeysPtr keysList, const EPNodePtr p ){
    404  |   EPTokenKeysPtr ptk;
    405  |
    406  |   ptk = (EPTokenKeysPtr) UT_malloc(sizeof(EPTokenKeys));
    407  |   ptk->isValidPGPSignature = p->isValidPGPSignature;
    408  |   ptk->keyID = p->keyID;
    409  |   ptk->next = NULL;
    410  |   if (keysList == NULL)
    411  |     return ptk;
    412  |   else {
    413  |     ptk->next = keysList;
    414  |     return ptk;
    415  |   }
    416  | }
    417  |
    418  | /* ------------------------------------------------- */
    419  |
    420  | EPTokenKeysPtr RemoveKeyInfo( const EPTokenKeysPtr keysHead ) {
    421  |   EPTokenKeysPtr tmp = keysHead->next;
    422  |
    423  |   free(keysHead);
    424  |   return tmp;
    425  | }
    426  | /* ------------------------------------------------- */
    427  |
    428  | EPTokenPtr EP_GetTokens(const EPNodePtr p, const EPTokenPtr head,
    429  | 			EPTokenKeysPtr keysList) {
    430  |   EPTokenPtr pt, ptmp = head;
    431  |   EPTokenKeysPtr kl = keysList;
    432  |
    433  |   if (p != NULL) {
    434  |     if (p->isValidPGPSignature != vS_IS_NOT_PGP ) {
    435  |       kl = AddKeyInfo(kl, p);
    436  |     }
    437  |     if (EP_HasContent(p)) {
    438  |       pt = EP_DefineNewToken(p->MIMEContentType, p->file, kl);
    439  |       if (ptmp != NULL) {
    440  | 	pt->next = ptmp;
    441  | 	ptmp->prev = pt;
    442  | 	ptmp = pt;
    443  |       } else
    444  | 	ptmp = pt;
    445  |     } else
    446  |       ptmp = EP_GetTokens(p->inner, ptmp, kl);
    447  |
    448  |     if (p->isValidPGPSignature != vS_IS_NOT_PGP ) {
    449  |       kl = RemoveKeyInfo(kl);
    450  |     }
    451  |
    452  |     ptmp = EP_GetTokens(p->next, ptmp, kl);
    453  |   }
    454  |   return ptmp;
    455  | }
    456  |
    457  | /* ------------------------------------------------- */
    458  | void EP_PrintTokens(EPTokenPtr head) {
    459  |   EPTokenPtr p = head;
    460  |   EPTokenKeysPtr ptk;
    461  |
    462  |   while (p != NULL) {
    463  |     printf("Token: %s, MIMEtype: %d\n", p->file, p->MIMEContentType);
    464  |     ptk = p->keys;
    465  |     while (ptk != NULL) {
    466  |       printf("     key: %0X, isValid: %s\n",
    467  | 	     ptk->keyID, vS_strRC[ptk->isValidPGPSignature]);
    468  |       ptk = ptk->next;
    469  |     }
    470  |     p = p->next;
    471  |   }
    472  | }
    473  |
    474  | /* ------------------------------------------------- */
    475  |
    476  | void EP_CleanTokens(const EPTokenPtr head) {
    477  |   EPTokenPtr prevp, p = head;
    478  |   EPTokenKeysPtr ptk, prevptk;
    479  |
    480  |   while (p != NULL) {
    481  |     ptk = p->keys;
    482  |     while (ptk != NULL) {
    483  |       prevptk = ptk;
    484  |       ptk = ptk->next;
    485  |       free(prevptk);
    486  |     }
    487  |     prevp = p;
    488  |     p = p->next;
    489  |     free(prevp);
    490  |   }
    491  | }
    492  |
    493  |