## modules/ep/mail_parser.c

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

## DEFINITIONS

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_GetPasswords
17. EP_GetTokens
18. EP_PrintTokens
19. EP_CleanTokens

       1 /***************************************
       2   $Revision: 1.33 $
       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 ) {
         /* [<][>][^][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   EP_Mail_DescrPtr ptr;
     110   char hostname[MAXHOSTNAMELEN];
     111   int retcode;
     112   long debug = 0;
     113   char mail_file[FILENAMELEN];
     114
     115   EP_Debug = debug;
     116
     117   gethostname(hostname, MAXHOSTNAMELEN);
     118   sprintf(EP_outputPrefix, "%s/EPMtmp.%s.%d.", outputPath,
     119           hostname, getpid());
     120   PA_SetOutputPrefix(EP_outputPrefix);
     121
     122   /*
     123   strcpy(EP_keyRing, keyRing);
     124   strcpy(EP_gpgcmd, gpgcmd);
     125   */
     126
     127   sprintf (mail_file,"%sunprocessed", EP_outputPrefix);      /* the file where the mail message will be stored */
     128
     129   /* if ((retcode = MM_store((char*)inputFile,mail_file, debug)) != 0)
     130     exit (retcode); */
     131
     132   MM_store((char*)inputFile,mail_file, debug, 0);
     133
     134   ptr = InitializeMailDescr(mail_file);
     135   /* Invoke the MIME parser */
     136   retcode = MM_extract_mime(mail_file, NULL, ptr->tree, debug);
     137
     138   return ptr;
     139 }
     140
     141 /* ------------------------------------------------- */
     142
     143 EPNodePtr EP_ParseText(const char *inputFile,
         /* [<][>][^][v][top][bottom][index][help] */
     144                        const char *outputPath) {
     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   /*
     155   strcpy(EP_keyRing, keyRing);
     156   strcpy(EP_gpgcmd, gpgcmd);
     157   */
     158
     159   ptr = EP_InitializeRootNode(inputFile);
     160
     161   PA_SetOutputPrefix(EP_outputPrefix);
     162   return PA_ParseMessage(ptr);
     163 }
     164
     165
     166 /* ------------------------------------------------- */
     167
     168 EPNodePtr EP_MIMEParse(const EPNodePtr p)
         /* [<][>][^][v][top][bottom][index][help] */
     169 {
     170   char mail_file[FILENAMELEN];
     171   int retcode;
     172   FILE * fin;
     173   char *strptr;
     174   int found = 0, headers_end = 0;
     175   char txt[MAX_LINE_BUF];
     176
     177   sprintf (mail_file,"%s%d.unprocessed", EP_outputPrefix, p->nodeID);      /* the file where the mail message will be stored */
     178
     179   PA_SetOutputPrefix(EP_outputPrefix);
     180   /* Quest for a mail header:
     181      look for a mail header of type (content-type || mime version).
     182   */
     183
     184   if ((fin = fopen(p->file, "r")) != NULL) {
     185     while ( !headers_end && !found &&
     186             (strptr = fgets(txt, MAX_LINE_BUF, fin)) != NULL) {
     187       if ( do_regex_test("^Content-Type:", txt) ||
     188            do_regex_test("^MIME-Version:", txt)) {
     189         found = 1;
     190         fclose(fin);
     191
     192         /* if ((retcode = MM_store((char*)p->file,mail_file, EP_Debug)) != 0) {
     193            fprintf(stderr, "Error on MM_Store: %d\n", retcode );
     194            } */
     195
     196         MM_store((char*)p->file,mail_file, EP_Debug, 0);
     197
     198         /* Invoke the MIME parser */
     199         retcode = MM_extract_mime(mail_file, NULL, p, EP_Debug);
     200       } else
     201         if ( do_regex_test("^ *\n", txt) )
     202           headers_end = 1;
     203     }
     204
     205     if (!found) {
     206       fclose(fin);
     207       PA_SetOutputPrefix(EP_outputPrefix);
     208
     209       PA_ParseMessage(p);
     210
     211     }
     212
     213   } else {
     214     p->isValidPGPSignature = vS_NO_IN_FILES;
     215   }
     216
     217   return p;
     218 }
     219
     220 /* ------------------------------------------------- */
     221
     222 EPNodePtr EP_InitializeRootNode( const char *inputFile ) {
         /* [<][>][^][v][top][bottom][index][help] */
     223   EPNodePtr rootNode;
     224
     225   EP_TreeHeight = EP_Node_ID = 0;
     226
     227   rootNode = UT_malloc(sizeof(struct EPNode));
     228
     229   rootNode->nodeID = 0;
     230   rootNode->isValidPGPSignature = vS_IS_NOT_PGP;
     231   rootNode->keyID = 0;
     232   rootNode->MIMEContentType = -1;
     233   rootNode->strMIMEContentType = NULL;
     234   rootNode->file = strdup(inputFile);
     235   rootNode->inner = NULL;
     236   rootNode->next = NULL;
     237
     238   return rootNode;
     239 }
     240
     241 /* ------------------------------------------------- */
     242
     243 EPNodePtr EP_InitializeNode( const char *inputFile, const int nodeID ) {
         /* [<][>][^][v][top][bottom][index][help] */
     244   EPNodePtr node;
     245
     246   node = UT_malloc(sizeof(struct EPNode));
     247
     248   node->nodeID = nodeID;
     249   node->isValidPGPSignature = vS_IS_NOT_PGP;
     250   node->keyID = 0;
     251   node->MIMEContentType = -1;
     252   node->strMIMEContentType = NULL;
     253   node->file = strdup(inputFile);
     254   node->inner = NULL;
     255   node->next = NULL;
     256
     257   return node;
     258 }
     259
     260 /* ------------------------------------------------- */
     261
     262 EPNodePtr EP_DefineNewNode( const int nodeID,
         /* [<][>][^][v][top][bottom][index][help] */
     263                             const short isValidPGPSignature,
     264                             const t_MM_type MIMEContentType,
     265                             const char *strMIMEContentType,
     266                             const u32 keyID) {
     267   EPNodePtr node;
     268
     269   node = (EPNodePtr) UT_malloc(sizeof(EP_mail_node));
     270
     271   /*  printf("node: %d, %p\n", nodeID, node); */
     272
     273   node->nodeID = nodeID;
     274   node->isValidPGPSignature = isValidPGPSignature;
     275   node->keyID = keyID;
     276   node->MIMEContentType = MIMEContentType;
     277   node->strMIMEContentType = (strMIMEContentType == NULL ? NULL :
     278                               strdup(strMIMEContentType) );
     279   node->inner = NULL;
     280   node->next = NULL;
     281   EP_BuildFilename(node);
     282
     283   return node;
     284 }
     285
     286 /* ------------------------------------------------- */
     287 /* Deallocate parsing tree and remove files */
     288
     289 void EP_TreeCleanUp(const EPNodePtr ptr) {
         /* [<][>][^][v][top][bottom][index][help] */
     290
     291   if (ptr->file != NULL) {
     292     unlink(ptr->file);
     293     /*    printf("node: %d, %p\n", ptr->nodeID, ptr); */
     294     free(ptr->file);
     295   }
     296   if (ptr->strMIMEContentType != NULL) {
     297     free(ptr->strMIMEContentType);
     298   }
     299
     300   if (ptr->inner != NULL) EP_TreeCleanUp(ptr->inner);
     301   if (ptr->next != NULL) EP_TreeCleanUp(ptr->next);
     302
     303   free(ptr);
     304 }
     305
     306 /* ------------------------------------------------- */
     307 void MailHeaderFieldCleanUp(Mail_Header_FieldPtr p) {
         /* [<][>][^][v][top][bottom][index][help] */
     308   Mail_Header_FieldPtr ptmp = p, prev;
     309
     310   while (ptmp != NULL) {
     311     prev = ptmp;
     312     ptmp = ptmp->next;
     313     if (prev->field != NULL)
     314       free(prev->field);
     315     free(prev);
     316   }
     317 }
     318
     319
     320 /* ------------------------------------------------- */
     321
     322 /* Deallocate parsing tree and remove files */
     323
     324 void EP_MailDescrCleanUp(const EP_Mail_DescrPtr ptr) {
         /* [<][>][^][v][top][bottom][index][help] */
     325
     326   if (ptr != NULL) {
     327
     328     MailHeaderFieldCleanUp(ptr->from);
     329     MailHeaderFieldCleanUp(ptr->subject);
     330     MailHeaderFieldCleanUp(ptr->date);
     331     MailHeaderFieldCleanUp(ptr->message_id);
     332     MailHeaderFieldCleanUp(ptr->reply_to);
     333     MailHeaderFieldCleanUp(ptr->cc);
     334     MailHeaderFieldCleanUp(ptr->content_type);
     335
     336     EP_TreeCleanUp(ptr->tree);
     337     free(ptr);
     338   }
     339 }
     340
     341 /* ------------------------------------------------- */
     342 /* Build a node filename */
     343
     344 void EP_BuildFilename(const EPNodePtr ptr) {
         /* [<][>][^][v][top][bottom][index][help] */
     345   char file[FILENAME_LENGTH];
     346
     347   sprintf(file, "%s%d", EP_outputPrefix, ptr->nodeID);
     348   ptr->file = strdup(file);
     349 }
     350
     351 /* ------------------------------------------------- */
     352
     353 void EP_ShowTree(const EPNodePtr p) {
         /* [<][>][^][v][top][bottom][index][help] */
     354   if (p != NULL) {
     355     /* if (EP_HasContent(p)) { */
     356       printf("Node ID: %d\n", p->nodeID);
     357       printf("isValidPGPSignature: %s\n",  vS_strRC[p->isValidPGPSignature]);
     358       printf("MIMEContentType: %d\n", p->MIMEContentType);
     359       printf("Key ID: %0X\n", p->keyID);
     360       printf("file: %s\n\n\n", p->file);
     361       /* } */
     362     if (p->inner != NULL)
     363       EP_ShowTree(p->inner);
     364     if (p->next != NULL)
     365       EP_ShowTree(p->next);
     366   }
     367 }
     368
     369 /* ------------------------------------------------- */
     370
     371 EPTokenPtr EP_DefineNewToken( const t_MM_type MIMEContentType,
         /* [<][>][^][v][top][bottom][index][help] */
     372                               const char *file,
     373                               const EPTokenKeysPtr keysList ) {
     374   EPTokenPtr token;
     375   EPTokenKeysPtr head = NULL, p = keysList, pnew, prev = NULL;
     376
     377   token = (EPTokenPtr) UT_malloc(sizeof(EPToken));
     378   token->file = (char*)file;
     379   token->MIMEContentType = MIMEContentType;
     380
     381
     382   /* generate head, and build the key list for this result node */
     383   if (p != NULL) {
     384     pnew = (EPTokenKeysPtr) UT_malloc(sizeof(EPTokenKeys));
     385     pnew->isValidPGPSignature = p->isValidPGPSignature;
     386     pnew->keyID = p->keyID;
     387     pnew->next = NULL;
     388     head = prev = pnew;
     389     p = p->next;
     390   }
     391
     392   while (p != NULL) {
     393     pnew = (EPTokenKeysPtr) UT_malloc(sizeof(EPTokenKeys));
     394     pnew->isValidPGPSignature = p->isValidPGPSignature;
     395     pnew->keyID = p->keyID;
     396     pnew->next = NULL;
     397     prev->next = pnew;
     398     prev = pnew;
     399     p = p->next;
     400   }
     401
     402   token->keys = head;
     403   token->next = token->prev = NULL;
     404
     405   return token;
     406 }
     407
     408 /* ------------------------------------------------- */
     409
     410 EPTokenKeysPtr AddKeyInfo( EPTokenKeysPtr keysList, const EPNodePtr p ){
         /* [<][>][^][v][top][bottom][index][help] */
     411   EPTokenKeysPtr ptk;
     412
     413   ptk = (EPTokenKeysPtr) UT_malloc(sizeof(EPTokenKeys));
     414   ptk->isValidPGPSignature = p->isValidPGPSignature;
     415   ptk->keyID = p->keyID;
     416   ptk->next = NULL;
     417   if (keysList == NULL)
     418     return ptk;
     419   else {
     420     ptk->next = keysList;
     421     return ptk;
     422   }
     423 }
     424
     425 /* ------------------------------------------------- */
     426
     427 EPTokenKeysPtr RemoveKeyInfo( const EPTokenKeysPtr keysHead ) {
         /* [<][>][^][v][top][bottom][index][help] */
     428   EPTokenKeysPtr tmp = keysHead->next;
     429
     430   free(keysHead);
     431   return tmp;
     432 }
     433
     434 /* ------------------------------------------------- */
     435
     436 /*
     437  ep_GetPasswords: collects all passwords in the current mail chunk
     438  */
     439 GSList* ep_GetPasswords(char *file) {
         /* [<][>][^][v][top][bottom][index][help] */
     440   FILE *input_file;
     441   gchar line[1024];
     442   GSList *password_list = NULL;
     443
     444   if ((input_file = fopen(file, "r")) == NULL) {
     445     ER_perror(FAC_UP, UP_CANTOPEN, "Couldn't open the file %s\n", file);
     446     exit(1);
     447   }
     448
     449   while (fgets(line, 1024, input_file) != NULL) {
     450     if (strncasecmp(line, "password:", 9) == 0 &&
     451         strlen(line) > 9) { // 9 = strlen 'password:'
     452       //printf("pwd add %s\n", g_strstrip(strdup(line + 9)));
     453       password_list = g_slist_append(password_list,
     454                                     g_strstrip(strdup(line + 9)));
     455     }
     456   }
     457
     458   fclose (input_file);
     459   return password_list;
     460 }
     461
     462 /* ------------------------------------------------- */
     463
     464 /*
     465
     466   Password transporting works as follows:
     467   Current node and siblings receive passwords from parent.
     468   Child nodes of the current one receive the ones that the
     469     current received plus the ones specified on the current.
     470  */
     471 EPTokenPtr EP_GetTokens(const EPNodePtr p, const EPTokenPtr head,
         /* [<][>][^][v][top][bottom][index][help] */
     472                         EPTokenKeysPtr keysList, GSList *passwords) {
     473   EPTokenPtr pt, ptmp = head;
     474   EPTokenKeysPtr kl = keysList;
     475   GSList *node_passwords = NULL;
     476
     477   if (p != NULL) {
     478     if (p->isValidPGPSignature != vS_IS_NOT_PGP ) {
     479       kl = AddKeyInfo(kl, p);
     480     }
     481     if (EP_HasContent(p)) {
     482       pt = EP_DefineNewToken(p->MIMEContentType, p->file, kl);
     483       pt->passwords = passwords;
     484       if (ptmp != NULL) {
     485         pt->next = ptmp;
     486         ptmp->prev = pt;
     487         ptmp = pt;
     488       } else
     489         ptmp = pt;
     490     }
     491     else {
     492       if (p->MIMEContentType<3) { //UGLY
     493         node_passwords = ep_GetPasswords(p->file);
     494         node_passwords = g_slist_concat(node_passwords, passwords);
     495       }
     496
     497       ptmp = EP_GetTokens(p->inner, ptmp, kl, node_passwords);
     498     }
     499
     500     if (p->isValidPGPSignature != vS_IS_NOT_PGP ) {
     501       kl = RemoveKeyInfo(kl);
     502     }
     503
     504     ptmp = EP_GetTokens(p->next, ptmp, kl, passwords);
     505   }
     506   return ptmp;
     507 }
     508
     509 /* ------------------------------------------------- */
     510 void EP_PrintTokens(EPTokenPtr head) {
         /* [<][>][^][v][top][bottom][index][help] */
     511   EPTokenPtr p = head;
     512   EPTokenKeysPtr ptk;
     513
     514   while (p != NULL) {
     515     printf("Token: %s, MIMEtype: %d\n", p->file, p->MIMEContentType);
     516     ptk = p->keys;
     517     while (ptk != NULL) {
     518       printf("     key: %0X, isValid: %s\n",
     519              ptk->keyID, vS_strRC[ptk->isValidPGPSignature]);
     520       ptk = ptk->next;
     521     }
     522     p = p->next;
     523   }
     524 }
     525
     526 /* ------------------------------------------------- */
     527
     528
     529 void EP_CleanTokens(const EPTokenPtr head) {
         /* [<][>][^][v][top][bottom][index][help] */
     530   EPTokenPtr prevp, p = head;
     531   EPTokenKeysPtr ptk, prevptk;
     532
     533   while (p != NULL) {
     534     ptk = p->keys;
     535     while (ptk != NULL) {
     536       prevptk = ptk;
     537       ptk = ptk->next;
     538       free(prevptk);
     539     }
     540     prevp = p;
     541     p = p->next;
     542     free(prevp);
     543   }
     544 }
     545
     546

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