## modules/ep/mail_parser.c

/* [<][>][^][v][top][bottom][index][help] */

## FUNCTIONS

This source file includes following functions.

1. InitializeMailDescr
2. EP_ParseMail
3. EP_ParseText
4. EP_MIMEParse
5. EP_InitializeRootNode
6. EP_InitializeNode
7. EP_DefineNewNode
8. EP_TreeCleanUp
9. MailHeaderFieldCleanUp
10. EP_MailDescrCleanUp
11. EP_BuildFilename
12. EP_ShowTree
13. EP_DefineNewToken
14. AddKeyInfo
15. RemoveKeyInfo
16. EP_GetTokens
17. EP_PrintTokens
18. EP_CleanTokens

       1 /***************************************
       2   $Revision: 1.26 $
       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                              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 ) {
         /* [<][>][^][v][top][bottom][index][help] */
      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,
         /* [<][>][^][v][top][bottom][index][help] */
     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.%ld.", 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,
         /* [<][>][^][v][top][bottom][index][help] */
     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.%ld.", 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)
         /* [<][>][^][v][top][bottom][index][help] */
     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 ) {
         /* [<][>][^][v][top][bottom][index][help] */
     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 ) {
         /* [<][>][^][v][top][bottom][index][help] */
     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,
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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,
         /* [<][>][^][v][top][bottom][index][help] */
     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 ){
         /* [<][>][^][v][top][bottom][index][help] */
     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 ) {
         /* [<][>][^][v][top][bottom][index][help] */
     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,
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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) {
         /* [<][>][^][v][top][bottom][index][help] */
     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

/* [<][>][^][v][top][bottom][index][help] */