home *** CD-ROM | disk | FTP | other *** search
/ Collection of Internet / Collection of Internet.iso / msdos / lynx / source / www / library / implemen / htmime.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-25  |  8.7 KB  |  365 lines

  1. /*            MIME Message Parse            HTMIME.c
  2. **            ==================
  3. **
  4. **    This is RFC 1341-specific code.
  5. **    The input stream pushed into this parser is assumed to be
  6. **    stripped on CRs, ie lines end with LF, not CR LF.
  7. **    (It is easy to change this except for the body part where
  8. **    conversion can be slow.)
  9. **
  10. ** History:
  11. **       Feb 92    Written Tim Berners-Lee, CERN
  12. **
  13. */
  14. #include"capalloc.h"
  15. #include "HTMIME.h"        /* Implemented here */
  16. #include "HTAlert.h"
  17. #include"capstdio.h"
  18.  
  19.  
  20. /*        MIME Object
  21. **        -----------
  22. */
  23.  
  24. typedef enum _MIME_state {
  25.     MIME_TRANSPARENT,    /* put straight through to target ASAP! */
  26.     BEGINNING_OF_LINE,
  27.     CONTENT_T,
  28.     CONTENT_TRANSFER_ENCODING,
  29.     CONTENT_TYPE,
  30.     SKIP_GET_VALUE,        /* Skip space then get value */
  31.     GET_VALUE,        /* Get value till white space */
  32.     JUNK_LINE,        /* Ignore the rest of this folded line */
  33.     NEWLINE,        /* Just found a LF .. maybe continuation */
  34.     CHECK,            /* check against check_pointer */
  35.     MIME_NET_ASCII,        /* Translate from net ascii */
  36.     MIME_IGNORE        /* ignore entire file */
  37.     /* TRANSPARENT and IGNORE are defined as stg else in _WINDOWS */
  38. } MIME_state;
  39.  
  40. #define VALUE_SIZE 128        /* @@@@@@@ Arbitrary? */
  41. struct _HTStream {
  42.     CONST HTStreamClass *    isa;
  43.     
  44.     BOOL            net_ascii;    /* Is input net ascii? */
  45.     MIME_state        state;        /* current state */
  46.     MIME_state        if_ok;        /* got this state if match */
  47.     MIME_state        field;        /* remember which field */
  48.     MIME_state        fold_state;    /* state on a fold */
  49.     CONST char *        check_pointer;    /* checking input */
  50.     
  51.     char *            value_pointer;    /* storing values */
  52.     char             value[VALUE_SIZE];
  53.     
  54.     HTParentAnchor *    anchor;        /* Given on creation */
  55.     HTStream *        sink;        /* Given on creation */
  56.     
  57.     char *            boundary;    /* For multipart */
  58.     
  59.     HTFormat        encoding;    /* Content-Transfer-Encoding */
  60.     HTFormat        format;        /* Content-Type */
  61.     HTStream *        target;        /* While writing out */
  62.     HTStreamClass        targetClass;
  63.     
  64.     HTAtom *        targetRep;    /* Converting into? */
  65. };
  66.  
  67.  
  68. /*_________________________________________________________________________
  69. **
  70. **            A C T I O N     R O U T I N E S
  71. */
  72.  
  73. /*    Character handling
  74. **    ------------------
  75. **
  76. **    This is a FSM parser which is tolerant as it can be of all
  77. **    syntax errors.  It ignores field names it does not understand,
  78. **    and resynchronises on line beginnings.
  79. */
  80.  
  81. PRIVATE void HTMIME_put_character ARGS2(HTStream *, me, char, c)
  82. {
  83.     if (me->state == MIME_TRANSPARENT) {
  84.         (*me->targetClass.put_character)(me->target, c);/* MUST BE FAST */
  85.     return;
  86.     }
  87.     
  88.     /* This slightly simple conversion just strips CR and turns LF to
  89.     ** newline. On unix LF is \n but on Mac \n is CR for example.
  90.     ** See NetToText for an implementation which preserves single CR or LF.
  91.     */
  92.     if (me->net_ascii) {
  93.         c = FROMASCII(c);
  94.     if (c == CR) return;
  95.     else if (c == LF) c = '\n';
  96.     }
  97.     
  98.     switch(me->state) {
  99.  
  100.     case MIME_IGNORE:
  101.         return;
  102.  
  103.     case MIME_TRANSPARENT:        /* Not reached see above */
  104.         (*me->targetClass.put_character)(me->target, c);
  105.     return;
  106.     
  107.     case MIME_NET_ASCII:
  108.         (*me->targetClass.put_character)(me->target, c); /* MUST BE FAST */
  109.     return;
  110.  
  111.     case NEWLINE:
  112.     if (c != '\n' && WHITE(c)) {        /* Folded line */
  113.         me->state = me->fold_state;    /* pop state before newline */
  114.         break;
  115.     }
  116.     
  117.     /*    else Falls through */
  118.     
  119.     case BEGINNING_OF_LINE:
  120.         switch(c) {
  121.     case 'c':
  122.     case 'C':
  123.         me->check_pointer = "ontent-t";
  124.         me->if_ok = CONTENT_T;
  125.         me->state = CHECK;
  126.         break;
  127.     case '\n':            /* Blank line: End of Header! */
  128.         {
  129. #ifndef RELEASE
  130.         if (TRACE) fprintf(stderr,
  131.             "HTMIME: MIME content type is %s, converting to %s\n",
  132.             HTAtom_name(me->format), HTAtom_name(me->targetRep));
  133. #endif /* RELEASE */
  134.         me->target = HTStreamStack(me->format, me->targetRep,
  135.              me->sink , me->anchor);
  136.         if (!me->target) {
  137. #ifndef RELEASE
  138.             if (TRACE) fprintf(stderr, "MIME: Can't translate! ** \n");
  139. #endif /* RELEASE */
  140.             me->target = me->sink;    /* Cheat */
  141.         }
  142.         if (me->target) {
  143.             me->targetClass = *me->target->isa;
  144.         /* Check for encoding and select state from there @@ */
  145.         
  146.             me->state = MIME_TRANSPARENT; /* From now push straigh through */
  147.         } else {
  148.             me->state = MIME_IGNORE;        /* What else to do? */
  149.         }
  150.         }
  151.         break;
  152.         
  153.     default:
  154.        goto bad_field_name;
  155.        break;
  156.        
  157.     } /* switch on character */
  158.         break;
  159.     
  160.     case CHECK:                /* Check against string */
  161.         if (TOLOWER(c) == *(me->check_pointer)++) {
  162.         if (!*me->check_pointer) me->state = me->if_ok;
  163.     } else {        /* Error */
  164. #ifndef RELEASE
  165.         if (TRACE) fprintf(stderr,
  166.         "HTMIME: Bad character `%c' found where `%s' expected\n",
  167.         c, me->check_pointer - 1);
  168. #endif /* RELEASE */
  169.         goto bad_field_name;
  170.     }
  171.     break;
  172.     
  173.     case CONTENT_T:
  174.         switch(c) {
  175.     case 'r':
  176.     case 'R':
  177.         me->check_pointer = "ansfer-encoding:";
  178.         me->if_ok = CONTENT_TRANSFER_ENCODING;
  179.         me->state = CHECK;
  180.         break;
  181.         
  182.     case 'y':
  183.     case 'Y':
  184.         me->check_pointer = "pe:";
  185.         me->if_ok = CONTENT_TYPE;
  186.         me->state = CHECK;
  187.         break;
  188.         
  189.     default:
  190.         goto bad_field_name;
  191.         
  192.     } /* switch on character */
  193.     break;
  194.     
  195.     case CONTENT_TYPE:
  196.     case CONTENT_TRANSFER_ENCODING:
  197.         me->field = me->state;        /* remember it */
  198.     me->state = SKIP_GET_VALUE;
  199.                 /* Fall through! */
  200.     case SKIP_GET_VALUE:
  201.         if (c == '\n') {
  202.        me->fold_state = me->state;
  203.        me->state = NEWLINE;
  204.        break;
  205.     }
  206.     if (WHITE(c)) break;    /* Skip white space */
  207.     
  208.     me->value_pointer = me->value;
  209.     me->state = GET_VALUE;   
  210.     /* Fall through to store first character */
  211.     
  212.     case GET_VALUE:
  213.         if (WHITE(c)) {            /* End of field */
  214.         *me->value_pointer = 0;
  215.         switch (me->field) {
  216.         case CONTENT_TYPE:
  217.             me->format = HTAtom_for(me->value);
  218.         break;
  219.         case CONTENT_TRANSFER_ENCODING:
  220.             me->encoding = HTAtom_for(me->value);
  221.         break;
  222.         default:        /* Should never get here */
  223.             break;
  224.         }
  225.     } else {
  226.         if (me->value_pointer < me->value + VALUE_SIZE - 1) {
  227.             *me->value_pointer++ = c;
  228.         break;
  229.         } else {
  230.             goto value_too_long;
  231.         }
  232.     }
  233.     /* Fall through */
  234.     
  235.     case JUNK_LINE:
  236.         if (c == '\n') {
  237.         me->state = NEWLINE;
  238.         me->fold_state = me->state;
  239.     }
  240.     break;
  241.     
  242.     
  243.     } /* switch on state*/
  244.     
  245.     return;
  246.     
  247. value_too_long:
  248. #ifndef RELEASE
  249.     if (TRACE) fprintf(stderr,
  250.     "HTMIME: *** Syntax error. (string too long)\n");
  251. #endif /* RELEASE */
  252.     
  253. bad_field_name:                /* Ignore it */
  254.     me->state = JUNK_LINE;
  255.     return;
  256.     
  257. }
  258.  
  259.  
  260.  
  261. /*    String handling
  262. **    ---------------
  263. **
  264. **    Strings must be smaller than this buffer size.
  265. */
  266. PRIVATE void HTMIME_put_string ARGS2(HTStream *, me, CONST char*, s)
  267. {
  268.     CONST char * p;
  269.     if (me->state == MIME_TRANSPARENT)        /* Optimisation */
  270.         (*me->targetClass.put_string)(me->target,s);
  271.     else if (me->state != MIME_IGNORE)
  272.         for (p=s; *p; p++) HTMIME_put_character(me, *p);
  273. }
  274.  
  275.  
  276. /*    Buffer write.  Buffers can (and should!) be big.
  277. **    ------------
  278. */
  279. PRIVATE void HTMIME_write ARGS3(HTStream *, me, CONST char*, s, int, l)
  280. {
  281.     CONST char * p;
  282.     if (me->state == MIME_TRANSPARENT)        /* Optimisation */
  283.         (*me->targetClass.put_block)(me->target, s, l);
  284.     else
  285.         for (p=s; p < s+l; p++) HTMIME_put_character(me, *p);
  286. }
  287.  
  288.  
  289.  
  290.  
  291. /*    Free an HTML object
  292. **    -------------------
  293. **
  294. */
  295. PRIVATE void HTMIME_free ARGS1(HTStream *, me)
  296. {
  297.     if (me->target) (*me->targetClass.free)(me->target);
  298.     free(me);
  299. }
  300.  
  301. /*    End writing
  302. */
  303.  
  304. PRIVATE void HTMIME_abort ARGS2(HTStream *, me, HTError, e)
  305. {
  306.     if (me->target) (*me->targetClass.abort)(me->target, e);
  307.     free(me);
  308. }
  309.  
  310.  
  311.  
  312. /*    Structured Object Class
  313. **    -----------------------
  314. */
  315. PRIVATE CONST HTStreamClass HTMIME =
  316. {        
  317.     "MIMEParser",
  318.     HTMIME_free,
  319.     HTMIME_abort,
  320.     HTMIME_put_character,
  321.     HTMIME_put_string,
  322.     HTMIME_write
  323. }; 
  324.  
  325.  
  326. /*    Subclass-specific Methods
  327. **    -------------------------
  328. */
  329.  
  330. PUBLIC HTStream* HTMIMEConvert ARGS3(
  331.     HTPresentation *,    pres,
  332.     HTParentAnchor *,    anchor,
  333.     HTStream *,        sink)
  334. {
  335.     HTStream* me;
  336.     
  337.     me = malloc(sizeof(*me));
  338.     if (me == NULL) outofmem(__FILE__, "HTML_new");
  339.     me->isa = &HTMIME;       
  340.  
  341.     me->sink =         sink;
  342.     me->anchor =     anchor;
  343.     me->target =     NULL;
  344.     me->state =     BEGINNING_OF_LINE;
  345.     me->format =     WWW_PLAINTEXT;
  346.     me->targetRep =     pres->rep_out;
  347.     me->boundary =     0;        /* Not set yet */
  348.     me->net_ascii =     NO;    /* Local character set */
  349.     return me;
  350. }
  351.  
  352. PUBLIC HTStream* HTNetMIME ARGS3(
  353.     HTPresentation *,    pres,
  354.     HTParentAnchor *,    anchor,
  355.     HTStream *,        sink)
  356. {
  357.     HTStream* me = HTMIMEConvert(pres,anchor, sink);
  358.     if (!me) return NULL;
  359.     
  360.     me->net_ascii = YES;
  361.     return me;
  362. }
  363.  
  364.  
  365.