packages icon
 /* multi.c -- local hacks at UNINETT by Sigmund Austigard 1992 */ /*
  *                         COPYRIGHT 1992
  *                            UNINETT
  *                       TRONDHEIM, NORWAY
  *                      ALL RIGHTS RESERVED.
  *
  * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
  * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY UNINETT. UNINETT MAKES NO
  * REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE.
  * IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
  *
  * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT
  * RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN
  * ADDITION TO THAT SET FORTH ABOVE.
  *
  * Permission to use, copy, modify, and distribute this software and its
  * documentation for  any  purpose  and  without  fee  is  hereby  granted,
 provided
  * that the above copyright notice appear in all copies and that both that
  * copyright notice and this permission notice appear in supporting
  * documentation, and that the name of Uninett not be used in advertising
  *  or  publicity  pertaining  to  distribution  of  the  software  without
 specific,
  * written prior permission.
  *
  */

 /*
  * Some parts of this file is code modified from code copyright 1987, 1989
  * Digital Equipment Corporation, and copyright 1991 Carnegie Mellon
  * University, Software Engineering Institute.
  */


 #ifdef MULTI

 #include <malloc.h> #include <strings.h>  #include  <sys/types.h>  #include
 <sys/stat.h> #include <X11/Xaw/Cardinals.h> #include "xmh.h"

 #include "multi.h" #include "tocintrnl.h"

 static Switches *InitSwitches() {
     Switches *switches = (Switches *)XtMalloc(sizeof(Switches));

     switches->contentType  = text;
     switches->contentSub   = plain;
     switches->encoding     = bit7;
     switches->charset      = usascii;
     switches->needBoundary = FALSE;
     switches->boundary     = NULL;

     return switches; }






 static void parseHeaders(buf, switches) String buf; Switches *switches; {
     String here = buf;
     String help;
     Boolean doublequote;
     Boolean singlequote;

     while (*here) {

         doublequote = singlequote = FALSE;

         /* Is this line a  Content-Type  or  Content-Transfer-Encoding?  */
         if  (!strncasecmp(here,  "Content-",  8)) {                      /*
 More spesific, Content-Type  */               if  (!strncasecmp(here  +  8,
 "Type:",  5))  {                  here  +=  strspn(here  +  13,  " ") + 13;
                 if  (!strncasecmp(here,  "text/",  5))  {
 switches->contentType    =    text;                          here   +=   5;
                        if    (!strncasecmp(here,     "plain",     5))     {
                         here     =     &here[strspn(here+5,     "    ")+5];
                         switches->contentSub = plain;                     }
                       else   if   (!strncasecmp(here,   "richtext",  8))  {
                         here    +=    strspn(here+8,    "    ")    +     8;
                         switches->contentSub  =  richtext;
 }                           while    (*here     &&     *here     !=     '0)
                         switch  (here[0])  {                           case
 ';':                               here  =  &here[strspn(here+1,  "  ")+1];
                               if   (!strncasecmp(here,  "charset=",  8))  {
                                 here += 8;
                                 if       (*here       ==       '"')       {
                                            doublequote        =       TRUE;
                                                                     here++;
                                 }                                        if
 (!strncasecmp(here,  "us-ascii",  8))  {
 switches->charset = usascii;                                     here += 8;
                                 }                                  else  if
 (!strncasecmp(here,                     "iso-8859-",                     9)
                                              &&     (here[10]     ==     '0
                                                 ||    here[10]    ==    ' '
                                                ||   here[10]   ==    '    '
                                                  ||    here[10]    ==    ''
                                                ||    (here[10]    ==    '"'
                                                        &&      doublequote)
                                                ||    (here[10]    ==    '''
                                                     &&   singlequote)))   {
                                         if      (here[10]      ==      '"')
                                         doublequote         =        FALSE;
                                       else    if    (here[10]    ==    ''')
                                         singlequote         =        FALSE;
                                              here           +=           9;
                                             switch         (*here)        {
                                                     case                '0:
                                                     case               ' ':
                                         printf("invalid          charset0);
                                         break;       /*       ERROR      */
                                         case   '1':   switches->charset   =
 iso88591;                                               here++;      break;
                                         case   '2':   switches->charset   =
 iso88592;                                               here++;      break;
                                         case   '3':   switches->charset   =
 iso88593;                                               here++;      break;
                                         case   '4':   switches->charset   =
 iso88594;                                               here++;      break;
                                         case   '5':   switches->charset   =
 iso88595;                                               here++;      break;
                                         case   '6':   switches->charset   =
 iso88596;                                               here++;      break;
                                         case   '7':   switches->charset   =
 iso88597;                                               here++;      break;
                                         case   '8':   switches->charset   =
 iso88598;                                               here++;      break;
                                         case   '9':   switches->charset   =
 iso88599;                                               here++;      break;
                                                                    default:
                                         printf("unknown    iso   set   %c0,
 *here);                                                             here++;
                                         break;       /*       ERROR      */
                                       }                                   }
                                 /*          else           ERROR         */
                                 if     (*here     ==      '"')      here++;
                                }                                   else   {
                                 printf("not  charset=,  but   %s0,   here);
                                 here  =  " ";                             }
                                                                      break;
                                                                    default:
                             {                                  char  *eoln;
                                 char                                   tmp;
                                 eoln       =       strchr(here,        '0);
                                 if                 (eoln)                 {
                                              tmp          =          *eoln;
                                              *eoln          =          ' ';
                                      printf("unrecognized   string   <%s>0,
 here);                                               *eoln      =      tmp;
                                              here          =          eoln;
                                 }                                         }
                                    break;                                 }
                                                         if          (*here)
                         here++;                                           }
                 else    if   (!strncasecmp(here,   "multipart/",   10))   {
                      switches->contentType  =  multipart;
 switches->needBoundary    =   TRUE;                         here   +=   10;
                        if    (!strncasecmp(here,     "mixed",     5))     {
                         here     =     &here[strspn(here+5,     "    ")+5];
                         switches->contentSub = mixed;                     }
                      else  if  (!strncasecmp(here,  "alternative",  11))  {
                         here    +=    strspn(here+8,    "    ")    +    11;
                         switches->contentSub         =         alternative;
                      }                       else  if   (!strncasecmp(here,
 "digest",  6))  {                          here += strspn(here+8, " ") + 6;
                         switches->contentSub  =  digest;
 }                        else  if  (!strncasecmp(here,  "parallel",  8))  {
                         here    +=    strspn(here+8,    "    ")    +     8;
                         switches->contentSub  =  parallel;
 }                           while    (*here     &&     *here     !=     '0)
                         switch  (here[0])  {                           case
 ';':                               here  +=  strspn(here+1,  "  ")   +   1;
                               if  (!strncasecmp(here,  "boundary=",  9))  {
                                 here                 +=                  9;
                                 for  (help = here; *help && *help != ';' &&
 *help    !=    '0;    help++)                                             ;
                                 help--;                                  if
 (*help)  {                                       int  left  =  help-here+1;
                                         Boolean     dquoted     =    FALSE;

 switches->boundary   =  XtMalloc(left+1);
 for     (help     =      switches->boundary;      left;      here++)      {
                                         switch           (*here)          {
                                                       case             '"':
                                                       if          (dquoted)
                                                 dquoted      =       FALSE;
                                                                        else
                                                 dquoted       =       TRUE;
                                                                      break;
                                                       case             '\':
                                                  if      (*(here+1))      {
                                                 here++;
                                                 left--;
                                                 *help++      =       *here;
                                                                           }
                                                                        else
                                                 *help++       =      *here;
                                                                      break;
                                                                    default:
                                                  *help++      =      *here;
                                                                      break;
                                         }
                                         left--;
                                       }
 *help           =           ' ';
 /*                                  *(switches->boundary +  (help-here))  =
 ' ';                                             here    =    help+2;    */
                                 }                                      else
                                       printf("error   reading   boundary0);
                               }                                   else    {
                                 printf("not   boundary=,  but  %s0,  here);
                                 here = " ";                               }
                                                                      break;
                                                                    default:
                               printf("unrecognized   string  <%s>0,  here);
                             here = " ";                              break;
                         }                                        if (*here)
                         here++;                                           }
                 else    if    (!strncasecmp(here,    "message/",    8))   {
                      switches->contentType  =  message;                   }
                 else   if   (!strncasecmp(here,   "application/",   12))  {
                     switches->contentType = application;                  }
                 else     if    (!strncasecmp(here,    "image/",    6))    {
                      switches->contentType   =   image;                   }
                 else     if    (!strncasecmp(here,    "audio/",    6))    {
                      switches->contentType   =   audio;                   }
                 else     if    (!strncasecmp(here,    "video/",    6))    {
                      switches->contentType   =   video;                   }
              }               /* Well, perhaps Content-Transfer-Encoding? */
             else if (!strncasecmp(&here[8],  "Transfer-Encoding:",  18))  {
                 here      =       &here[strspn(&here[26],     "     ")+26];
                 if  (!strncasecmp(here,  "7bit",  4))  {
 here += 4;                     switches->encoding = bit7;                 }
                 else if (!strncasecmp(here, "8bit", 4)) {
 here += 4;                     switches->encoding = bit8;                 }
                 else    if    (!strncasecmp(here,    "binary",    6))     {
                      here  +=  6;                      switches->encoding =
 binary;                  }                  else   if   (!strncasecmp(here,
 "base64",   6))   {                         here   +=  6;
 switches->encoding  =  base64;                  }                  else  if
 (!strncasecmp(here,  "quoted-printable", 16)) {                     here +=
 16;                       switches->encoding  =  quoted;                  }
                 else                        printf("unknown  encoding  %s0,
 here);              }               else                  while  (*here  &&
 *here++  !=  '0)                       ;          }         else {
 while (*here && *here++ != '0)                 ;         }
     }
     return; }


 static UString ReadFileIntoBuffer(filename) String filename; {
     FILEPTR fid;
     UString buf;
     size_t size, ret;
     struct stat statstruct;

     stat(filename, &statstruct);
     size = statstruct.st_size;

     fid = fopen(filename, "r");

     buf = (UString)XtMalloc(size+1);
     ret = fread(buf, sizeof(u_char), size+1, fid);

     *(buf+size) = ' ';

     fclose(fid);

     return (buf); }

 /*
  * SplitBufferInto4();
  *
  * Splits a message as read from disk into four separate strings.
  *
  * Arguments:
  * hdr:         On entry, a pointer to a string
  *              (i.e. 'unsigned char **hdr')
  *              containing the buffer that is to be split.
  *              On return, the same pointer, but the string is now
  *              containing the unmodified headers of the message only.
  *              The 'msg' string resides in the same buffer, see below.
  * hdr2:        On entry a pointer to a pointer to NULL (hopefully)
  *              On return, a pointer to a string containing
  *              the headers, where all continuated headers have been
  *              joined. This makes the parsing in parseHeaders()
  *              easier.
  * bdr:         On entry a pointer to a pointer to NULL
  *              On return, a pointer to a string containing
  *              the line separating the headers and the body
  * msg:         On entry a pointer to a pointer to NULL
  *              On return, a pointer to a string containing
  *              the body of the message.
  *
  * Returns:
  * Void, but leaves the results in the memomry locations pointed to
  * by the arguments.
  *
  * WARNING:
  * This version splits the 'msg' part inplace, i.e. it is never malloc'ed
  * memory for a copy nor actually copied, but it is returned as a part of
  * the 'hdr' buffer. This should be considered when freeing 'hdr', and
  * when attempting to free 'msg'. THE RESULTS OF THIS OPERATION IS VERY
  * UNPREDICTABLE AND SHOULD NOT BE ATTEMPTED. Free 'hdr' instead, if
  * you don't need them anymore.
  *
  * The major benefit of implementing it this way is that you don't waste
  * cpu cycles and memory duplicating the possibly large body part of the
  * message yet another time. This is important, as MIME messages
  * tend to be large.
  * We have to duplicate this buffer a few times later on, anyhow :(
  */ static void SplitBufferInto4(hdr, hdr2, bdr, msg) UString *hdr,  *hdr2,
 *bdr, *msg; {
     UString buf = *hdr;
     UString hdrbuf, hdr2buf, bdrbuf, msgbuf, help, help2;
     u_char temp;

     for (help = buf; *help; help++)         if (*help == '0)             if
 (*(help + 1) == '0 ||                 (*(help+1) == '-' && *(help+2) == '-'
 && *(help+3) == '-')) {                 for  (help2  =  ++help;  *help2  &&
 *help2 != '0; help2++)                     ;

                 help2++;                       temp        =        *help2;
                 *help2  =  ' ';                                    bdrbuf =
 (UString)XtNewString((String)help);                    *help2    =    temp;
                 *help = ' ';                 break;             }

     hdrbuf = buf;

     hdr2buf = (UString)XtNewString((String)hdrbuf);
     for (help = hdr2buf; *help; help++)         if (*help ==  '0)
 if (*(help + 1) == ' ' || *(help + 1) == '')                 *help = ' ';

     *hdr  = hdrbuf;
     *hdr2 = hdr2buf;
     *bdr  = bdrbuf;
     *msg  = help2;

     return; }

 #undef D #define D(s) s

 void ParseMimeMessage(filename) String filename; {

     UString border, buf, hdrbuf2, msgbuf, out;
     int fd;
     Switches *switches = NULL;
     u_char tmp;

     if (!strcmp(filename, "/dev/null"))         return;

     switches = InitSwitches();

     buf = ReadFileIntoBuffer(filename);

     SplitBufferInto4(&buf, &hdrbuf2, &border, &msgbuf);

     parseHeaders(hdrbuf2, switches);

     XtFree((String)hdrbuf2);



     switch (switches->contentType) {
       case text:          D(printf("Contents:  text0));              switch
 (switches->contentSub)     {                   case     plain:
 D(printf("Subtype:  plain0));  break;             case  richtext:
 D(printf("Subtype:   richtext0));   break;               default:
 D(printf("Unknown subtype0)); break;         }         break;
       case     multipart:             D(printf("Contents:     multipart0));
         switch  (switches->contentSub)  {             case  mixed:
 D(printf("Subtype: mixed0)); break;            case  alternative:
 D(printf("Subtype:  alternative0));  break;           case digest:
 D(printf("Subtype: digest0));  break;             case  parallel:
 D(printf("Subtype:   parallel0));   break;               default:
 D(printf("Unknown subtype0)); break;         }         break;
       case message:         D(printf("Contents: message0));          switch
 (switches->contentSub)     {                   case     rfc822:
 D(printf("Subtype:  rfc8220));  break;             case  partial:
 D(printf("Subtype: partial0)); break;           case externalbody:
 D(printf("Subtype:  externalbody0));  break;             default:
 D(printf("Unknown subtype0)); break;         }         break;
       case   application:            D(printf("Contents:    application0));
         switch   (switches->contentSub)   {              case  octetstream:
              D(printf("Subtype:  octetstream0));  break;               case
 postscript:               D(printf("Subtype: postscript0)); break;
 case oda:             D(printf("Subtype: oda0)); break;            default:
             D(printf("Unknown subtype0)); break;         }         break;
       case  image:          D(printf("Contents:  image0));           switch
 (switches->contentSub)      {                   case     jpeg:
 D(printf("Subtype:   jpeg0));   break;               case   gif:
 D(printf("Subtype:    gif0));    break;                 default:
 D(printf("Unknown subtype0)); break;         }         break;
       case  audio:          D(printf("Contents:  audio0));           switch
 (switches->contentSub)     {                   case     basic:
 D(printf("Subtype:   basic0));   break;                default:
 D(printf("Unknown subtype0)); break;         }         break;
       case  video:          D(printf("Contents:  video0));           switch
 (switches->contentSub)      {                   case     mpeg:
 D(printf("Subtype:   mpeg0));   break;                 default:
 D(printf("Unknown subtype0)); break;         }         break;
       default:         D(printf("Unknown contents0)); break;
     }

     switch (switches->encoding) {
       case bit7:         D(printf("Encoding: 7 bit0)); break;
       case bit8:         D(printf("Encoding: 8 bit0)); break;
       case binary:         D(printf("Encoding: binary0)); break;
       case base64:         D(printf("Encoding: base640)); break;
       case quoted:         D(printf("Encoding: quoted-printable0)); break;
       default:         D(printf("Unknown encoding0)); break;
     }

     switch (switches->charset) {
       case usascii:         D(printf("Charset: us-ascii0)); break;
       case iso88591:
         D(printf("Charset: iso-8859-10)); break;
       case iso88592:
         D(printf("Charset: iso-8859-20)); break;
       case iso88593:
         D(printf("Charset: iso-8859-30)); break;
       case iso88594:
         D(printf("Charset: iso-8859-40)); break;
       case iso88595:
         D(printf("Charset: iso-8859-50)); break;
       case iso88596:
         D(printf("Charset: iso-8859-60)); break;
       case iso88597:         D(printf("Charset: iso-8859-70)); break;
       case iso88598:         D(printf("Charset: iso-8859-80)); break;
       case iso88599:         D(printf("Charset: iso-8859-90)); break;
       default:         D(printf("Unknown charset0)); break;
     }

     if (switches->needBoundary)         D(printf("Need boundary0));
     else         D(printf("Don't need boundary0));
     if (switches->boundary)         D(printf("Boundary: ->%s<-0,  switches-
 >boundary));
     else         D(printf("No boundary found0));

     out = (UString)XtMalloc(strlen(buf) + strlen(border) + strlen(msgbuf) +
 1);
     strcpy(out, buf);
     strcat(out, border);
     strcat(out, msgbuf);


     XtFree((String)buf);
     XtFree((String)border);

     if (switches->boundary)
         XtFree(switches->boundary);
     XtFree((String)switches);

     return; }







 #endif /* MULTI */