home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libmime / mimestub.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  31.5 KB  |  1,222 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /* mimestub.c --- junk to let libmime.a be tested standalone.
  20.    Created: Jamie Zawinski <jwz@netscape.com>, 15-May-96.
  21.  */
  22.  
  23. /* 
  24.    mimestub.c --- junk to let libmime.a be tested standalone.
  25.  
  26.    The junk in this file is various bits and pieces that have been
  27.    cut-and-pasted from other places in Mozilla, mainly netlib.  We just
  28.    copied these functions to avoid pulling in the spaghetti that is netlib,
  29.    and libxp, and libmsg, and and and...
  30.  
  31.    In addition to this file, we link directly against lib/xp/xp_file.o,
  32.    lib/xp/xp_str.o, and lib/libmsg/addr.o, because those files *actually
  33.    stand on their own*!
  34.  
  35.    Life kinda s#$%s, but oh well.
  36.  */
  37.  
  38. #include "xp.h"
  39.  
  40.  
  41. #ifndef XP_UNIX
  42. ERROR!    this is a unix-only file for the "mimefilt" standalone program.
  43.         This does not go into libmime.a.
  44. #endif
  45.  
  46.  
  47. #include <netdb.h>
  48.  
  49. #define CONST const
  50.  
  51. extern int MK_MSG_MIME_MAC_FILE;
  52. extern int MK_MSG_NO_HEADERS;
  53. extern int MK_OUT_OF_MEMORY;
  54. extern int MK_UNABLE_TO_OPEN_TMP_FILE;
  55.  
  56. /* recommended by comment in lib/xp/xp_intl.c... */
  57. char *
  58. XP_GetString(int16 i)
  59. {
  60.     extern char * XP_GetBuiltinString(int16 i);
  61.  
  62.     return XP_GetBuiltinString(i);
  63. }
  64.  
  65. int16 INTL_CharSetNameToID(char *charset) { return 0; }
  66. char *XP_GetStringForHTML (int i, int16 wincsid, char* english)
  67. {
  68.   return english; 
  69. }
  70.  
  71.  
  72. /* from nspr somewhere...
  73.  */
  74. struct hostent *
  75. PR_gethostbyname(const char *name)
  76. {
  77.   return gethostbyname(name);
  78. }
  79.  
  80.  
  81.  
  82. /* from libnet/mkutils.c */
  83. PUBLIC char *
  84. NET_EscapeHTML(const char * string)
  85. {
  86.     char *rv = (char *) XP_ALLOC(XP_STRLEN(string)*4 + 1); /* The +1 is for
  87.                                                               the trailing
  88.                                                               null! */
  89.     char *ptr = rv;
  90.  
  91.     if(rv)
  92.       {
  93.         for(; *string != '\0'; string++)
  94.           {
  95.             if(*string == '<')
  96.               {
  97.                 *ptr++ = '&';
  98.                 *ptr++ = 'l';
  99.                 *ptr++ = 't';
  100.                 *ptr++ = ';';
  101.               }
  102.             else if(*string == '>')
  103.               {
  104.                 *ptr++ = '&';
  105.                 *ptr++ = 'g';
  106.                 *ptr++ = 't';
  107.                 *ptr++ = ';';
  108.               }
  109.             else if(*string == '&')
  110.               {
  111.                 *ptr++ = '&';
  112.                 *ptr++ = 'a';
  113.                 *ptr++ = 'm';
  114.                 *ptr++ = 'p';
  115.                 *ptr++ = ';';
  116.               }
  117.             else
  118.               {
  119.                 *ptr++ = *string;
  120.               }
  121.           }
  122.         *ptr = '\0';
  123.       }
  124.  
  125.     return(rv);
  126. }
  127.  
  128.  
  129. /* from libnet/mkutils.c */
  130. # define MSG_FONT           int
  131. # define MSG_PlainFont      0
  132. # define MSG_BoldFont       1
  133. # define MSG_ItalicFont     2
  134. # define MSG_BoldItalicFont 3
  135. # define MSG_CITATION_SIZE  int
  136. # define MSG_NormalSize     4
  137. # define MSG_Bigger         5
  138. # define MSG_Smaller        6
  139. static int MSG_CitationFont = MSG_ItalicFont;
  140. static int MSG_CitationSize = MSG_NormalSize;
  141. static const char *MSG_CitationColor = 0;
  142.  
  143. #ifndef MOZILLA_30
  144. # define MSG_Prefs void
  145. # define MSG_GetCitationStyle(w,x,y,z) do{}while(0)
  146. # define MSG_GetPrefs(x) 0
  147. #endif
  148.  
  149. /* from libnet/mkutils.c */
  150. PUBLIC int
  151. NET_ScanForURLs(
  152. #ifndef MOZILLA_30
  153.                 MSG_Pane* pane,
  154. #endif /* !MOZILLA_30 */
  155.                 const char *input, int32 input_size,
  156.                 char *output, int output_size, XP_Bool urls_only)
  157. {
  158.   int col = 0;
  159.   const char *cp;
  160.   const char *end = input + input_size;
  161.   char *output_ptr = output;
  162.   char *end_of_buffer = output + output_size - 40; /* add safty zone :( */
  163.   Bool line_is_citation = FALSE;
  164.   const char *cite_open1, *cite_close1;
  165.   const char *cite_open2, *cite_close2;
  166. #ifndef MOZILLA_30
  167.   const char* color = NULL;
  168. #else  /* MOZILLA_30 */
  169.   const char* color = MSG_CitationColor;
  170. #endif /* MOZILLA_30 */
  171.  
  172.   if (urls_only)
  173.     {
  174.       cite_open1 = cite_close1 = "";
  175.       cite_open2 = cite_close2 = "";
  176.     }
  177.   else
  178.     {
  179. #ifdef MOZILLA_CLIENT
  180. # ifdef MOZILLA_30
  181.       MSG_FONT font = MSG_CitationFont;
  182.       MSG_CITATION_SIZE size = MSG_CitationSize;
  183. # else  /* !MOZILLA_30 */
  184.       MSG_Prefs* prefs;
  185.       MSG_FONT font = MSG_ItalicFont;
  186.       MSG_CITATION_SIZE size = MSG_NormalSize;
  187.  
  188.       if (pane) {
  189.         prefs = MSG_GetPrefs(pane);
  190.         MSG_GetCitationStyle(prefs, &font, &size, &color);
  191.       }
  192. #endif /* !MOZILLA_30 */
  193.       switch (font)
  194.         {
  195.         case MSG_PlainFont:
  196.           cite_open1 = "", cite_close1 = "";
  197.           break;
  198.         case MSG_BoldFont:
  199.           cite_open1 = "<B>", cite_close1 = "</B>";
  200.           break;
  201.         case MSG_ItalicFont:
  202.           cite_open1 = "<I>", cite_close1 = "</I>";
  203.           break;
  204.         case MSG_BoldItalicFont:
  205.           cite_open1 = "<B><I>", cite_close1 = "</I></B>";
  206.           break;
  207.         default:
  208.           XP_ASSERT(0);
  209.           cite_open1 = cite_close1 = "";
  210.           break;
  211.         }
  212.       switch (size)
  213.         {
  214.         case MSG_NormalSize:
  215.           cite_open2 = "", cite_close2 = "";
  216.           break;
  217.         case MSG_Bigger:
  218.           cite_open2 = "<FONT SIZE=\"+1\">", cite_close2 = "</FONT>";
  219.           break;
  220.         case MSG_Smaller:
  221.           cite_open2 = "<FONT SIZE=\"-1\">", cite_close2 = "</FONT>";
  222.           break;
  223.         default:
  224.           XP_ASSERT(0);
  225.           cite_open2 = cite_close2 = "";
  226.           break;
  227.         }
  228. #else  /* !MOZILLA_CLIENT */
  229.         XP_ASSERT(0);
  230. #endif /* !MOZILLA_CLIENT */
  231.     }
  232.  
  233.   if (!urls_only)
  234.     {
  235.       /* Decide whether this line is a quotation, and should be italicized.
  236.          This implements the following case-sensitive regular expression:
  237.  
  238.             ^[ \t]*[A-Z]*[]>]
  239.  
  240.          Which matches these lines:
  241.  
  242.             > blah blah blah
  243.                  > blah blah blah
  244.             LOSER> blah blah blah
  245.             LOSER] blah blah blah
  246.        */
  247.       const char *s = input;
  248.       while (s < end && XP_IS_SPACE (*s)) s++;
  249.       while (s < end && *s >= 'A' && *s <= 'Z') s++;
  250.  
  251.       if (s >= end)
  252.         ;
  253.       else if (input_size >= 6 && *s == '>' &&
  254.                !XP_STRNCMP (input, ">From ", 6))    /* #$%^ing sendmail... */
  255.         ;
  256.       else if (*s == '>' || *s == ']')
  257.         {
  258.           line_is_citation = TRUE;
  259.           XP_STRCPY(output_ptr, cite_open1);
  260.           output_ptr += XP_STRLEN(cite_open1);
  261.           XP_STRCPY(output_ptr, cite_open2);
  262.           output_ptr += XP_STRLEN(cite_open2);
  263.           if (color &&
  264.               output_ptr + XP_STRLEN(color) + 20 < end_of_buffer) {
  265.             XP_STRCPY(output_ptr, "<FONT COLOR=");
  266.             output_ptr += XP_STRLEN(output_ptr);
  267.             XP_STRCPY(output_ptr, color);
  268.             output_ptr += XP_STRLEN(output_ptr);
  269.             XP_STRCPY(output_ptr, ">");
  270.             output_ptr += XP_STRLEN(output_ptr);
  271.           }
  272.         }
  273.     }
  274.  
  275.   /* Normal lines are scanned for buried references to URL's
  276.      Unfortunately, it may screw up once in a while (nobody's perfect)
  277.    */
  278.   for(cp = input; cp < end && output_ptr < end_of_buffer; cp++)
  279.     {
  280.       /* if NET_URL_Type returns true then it is most likely a URL
  281.          But only match protocol names if at the very beginning of
  282.          the string, or if the preceeding character was not alphanumeric;
  283.          this lets us match inside "---HTTP://XXX" but not inside of
  284.          things like "NotHTTP://xxx"
  285.        */
  286.       int type = 0;
  287.       if(!XP_IS_SPACE(*cp) &&
  288.          (cp == input || (!XP_IS_ALPHA(cp[-1]) && !XP_IS_DIGIT(cp[-1]))) &&
  289.          (type = NET_URL_Type(cp)) != 0)
  290.         {
  291.           const char *cp2;
  292. #if 0
  293.           Bool commas_ok = (type == MAILTO_TYPE_URL);
  294. #endif
  295.  
  296.           for(cp2=cp; cp2 < end; cp2++)
  297.             {
  298.               /* These characters always mark the end of the URL. */
  299.               if (XP_IS_SPACE(*cp2) ||
  300.                   *cp2 == '<' || *cp2 == '>' ||
  301.                   *cp2 == '`' || *cp2 == ')' ||
  302.                   *cp2 == '\'' || *cp2 == '"' ||
  303.                   *cp2 == ']' || *cp2 == '}'
  304. #if 0
  305.                   || *cp2 == '!'
  306. #endif
  307.                   )
  308.                 break;
  309.  
  310. #if 0
  311.               /* But a "," marks the end of the URL only if there was no "?"
  312.                  earlier in the URL (this is so we can do imagemaps, like
  313.                  "foo.html?300,400".)
  314.                */
  315.               else if (*cp2 == '?')
  316.                 commas_ok = TRUE;
  317.               else if (*cp2 == ',' && !commas_ok)
  318.                 break;
  319. #endif
  320.             }
  321.  
  322.           /* Check for certain punctuation characters on the end, and strip
  323.              them off. */
  324.           while (cp2 > cp && 
  325.                  (cp2[-1] == '.' || cp2[-1] == ',' || cp2[-1] == '!' ||
  326.                   cp2[-1] == ';' || cp2[-1] == '-' || cp2[-1] == '?' ||
  327.                   cp2[-1] == '#'))
  328.             cp2--;
  329.  
  330.           col += (cp2 - cp);
  331.  
  332.           /* if the url is less than 7 characters then we screwed up
  333.            * and got a "news:" url or something which is worthless
  334.            * to us.  Exclude the A tag in this case.
  335.            *
  336.            * Also exclude any URL that ends in a colon; those tend
  337.            * to be internal and magic and uninteresting.
  338.            *
  339.            * And also exclude the builtin icons, whose URLs look
  340.            * like "internal-gopher-binary".
  341.            */
  342.           if (cp2-cp < 7 ||
  343.               (cp2 > cp && cp2[-1] == ':') ||
  344.               !XP_STRNCMP(cp, "internal-", 9))
  345.             {
  346.               XP_MEMCPY(output_ptr, cp, cp2-cp);
  347.               output_ptr += (cp2-cp);
  348.               *output_ptr = 0;
  349.             }
  350.           else
  351.             {
  352.               char *quoted_url;
  353.               int32 size_left = output_size - (output_ptr-output);
  354.  
  355.               if(cp2-cp > size_left)
  356.                 return MK_OUT_OF_MEMORY;
  357.  
  358.               XP_MEMCPY(output_ptr, cp, cp2-cp);
  359.               output_ptr[cp2-cp] = 0;
  360.               quoted_url = NET_EscapeHTML(output_ptr);
  361.               if (!quoted_url) return MK_OUT_OF_MEMORY;
  362.               PR_snprintf(output_ptr, size_left,
  363.                           "<A HREF=\"%s\">%s</A>",
  364.                           quoted_url,
  365.                           quoted_url);
  366.               output_ptr += XP_STRLEN(output_ptr);
  367.               XP_FREE(quoted_url);
  368.               output_ptr += XP_STRLEN(output_ptr);
  369.             }
  370.  
  371.           cp = cp2-1;  /* go to next word */
  372.         }
  373.       else
  374.         {
  375.           /* Make sure that special symbols don't screw up the HTML parser
  376.            */
  377.           if(*cp == '<')
  378.             {
  379.               XP_STRCPY(output_ptr, "<");
  380.               output_ptr += 4;
  381.               col++;
  382.             }
  383.           else if(*cp == '>')
  384.             {
  385.               XP_STRCPY(output_ptr, ">");
  386.               output_ptr += 4;
  387.               col++;
  388.             }
  389.           else if(*cp == '&')
  390.             {
  391.               XP_STRCPY(output_ptr, "&");
  392.               output_ptr += 5;
  393.               col++;
  394.             }
  395.           else
  396.             {
  397.               *output_ptr++ = *cp;
  398.               col++;
  399.             }
  400.         }
  401.     }
  402.  
  403.   *output_ptr = 0;
  404.  
  405.   if (line_is_citation)    /* Close off the highlighting */
  406.     {
  407.       if (color) {
  408.         XP_STRCPY(output_ptr, "</FONT>");
  409.         output_ptr += XP_STRLEN(output_ptr);
  410.       }
  411.  
  412.       XP_STRCPY(output_ptr, cite_close2);
  413.       output_ptr += XP_STRLEN (cite_close2);
  414.       XP_STRCPY(output_ptr, cite_close1);
  415.       output_ptr += XP_STRLEN (cite_close1);
  416.     }
  417.  
  418.   return 0;
  419. }
  420.  
  421.  
  422. /* from libnet/mkutils.c */
  423. PUBLIC int 
  424. NET_URL_Type (CONST char *URL)
  425. {
  426.     /* Protect from SEGV */
  427.     if (!URL || (URL && *URL == '\0'))
  428.         return(0);
  429.  
  430.     switch(*URL) {
  431.     case 'a':
  432.     case 'A':
  433.         if(!strncasecomp(URL,"about:security", 14))
  434.             return(SECURITY_TYPE_URL);
  435.         else if(!strncasecomp(URL,"about:",6))
  436.             return(ABOUT_TYPE_URL);
  437.         break;
  438.     case 'f':
  439.     case 'F':
  440.         if(!strncasecomp(URL,"ftp:",4))
  441.             return(FTP_TYPE_URL);
  442.         else if(!strncasecomp(URL,"file:",5))
  443.             return(FILE_TYPE_URL);
  444.         break;
  445.     case 'g':
  446.     case 'G':
  447.         if(!strncasecomp(URL,"gopher:",7)) 
  448.             return(GOPHER_TYPE_URL);
  449.         break;
  450.     case 'h':
  451.     case 'H':
  452.         if(!strncasecomp(URL,"http:",5))
  453.             return(HTTP_TYPE_URL);
  454.         else if(!strncasecomp(URL,"https:",6))
  455.             return(SECURE_HTTP_TYPE_URL);
  456.         break;
  457.     case 'i':
  458.     case 'I':
  459.         if(!strncasecomp(URL,"internal-gopher-",16))
  460.             return(INTERNAL_IMAGE_TYPE_URL);
  461.         else if(!strncasecomp(URL,"internal-news-",14))
  462.             return(INTERNAL_IMAGE_TYPE_URL);
  463.         else if(!strncasecomp(URL,"internal-edit-",14))
  464.             return(INTERNAL_IMAGE_TYPE_URL);
  465.         else if(!strncasecomp(URL,"internal-attachment-",20))
  466.             return(INTERNAL_IMAGE_TYPE_URL);
  467.         else if(!strncasecomp(URL,"internal-dialog-handler",23))
  468.             return(HTML_DIALOG_HANDLER_TYPE_URL);
  469.         else if(!strncasecomp(URL,"internal-panel-handler",22))
  470.             return(HTML_PANEL_HANDLER_TYPE_URL);
  471.         else if(!strncasecomp(URL,"internal-security-",18))
  472.             return(INTERNAL_SECLIB_TYPE_URL);
  473.         break;
  474.     case 'j':
  475.     case 'J':
  476.         if(!strncasecomp(URL, "javascript:",11))
  477.             return(MOCHA_TYPE_URL);
  478.         break;
  479.     case 'l':
  480.     case 'L':
  481.         if(!strncasecomp(URL, "livescript:",11))
  482.             return(MOCHA_TYPE_URL);
  483.         break;
  484.     case 'm':
  485.     case 'M':
  486.         if(!strncasecomp(URL,"mailto:",7)) 
  487.             return(MAILTO_TYPE_URL);
  488.         else if(!strncasecomp(URL,"mailbox:",8))
  489.             return(MAILBOX_TYPE_URL);
  490.         else if(!strncasecomp(URL, "mocha:",6))
  491.             return(MOCHA_TYPE_URL);
  492.         break;
  493.     case 'n':
  494.     case 'N':
  495.         if(!strncasecomp(URL,"news:",5))
  496.             return(NEWS_TYPE_URL);
  497. #ifdef NFS_TYPE_URL
  498.         else if(!strncasecomp(URL,"nfs:",4))
  499.             return(NFS_TYPE_URL);
  500. #endif /* NFS_TYPE_URL */
  501.         break;
  502.     case 'p':
  503.     case 'P':
  504.         if(!strncasecomp(URL,"pop3:",5))
  505.             return(POP3_TYPE_URL);
  506.         break;
  507.     case 'r':
  508.     case 'R':
  509.         if(!strncasecomp(URL,"rlogin:",7))
  510.             return(RLOGIN_TYPE_URL);
  511.         break;
  512.     case 's':
  513.     case 'S':
  514.         if(!strncasecomp(URL,"snews:",6))
  515.             return(NEWS_TYPE_URL);
  516.     case 't':
  517.     case 'T':
  518.         if(!strncasecomp(URL,"telnet:",7))
  519.             return(TELNET_TYPE_URL);
  520.         else if(!strncasecomp(URL,"tn3270:",7))
  521.             return(TN3270_TYPE_URL);
  522.         break;
  523.     case 'v':
  524.     case 'V':
  525.         if(!strncasecomp(URL, VIEW_SOURCE_URL_PREFIX, 
  526.                               sizeof(VIEW_SOURCE_URL_PREFIX)-1))
  527.             return(VIEW_SOURCE_TYPE_URL);
  528.         break;
  529.     case 'w':
  530.     case 'W':
  531.         if(!strncasecomp(URL,"wais:",5))
  532.             return(WAIS_TYPE_URL);
  533.         break;
  534.     case 'u':
  535.     case 'U':
  536.         if(!strncasecomp(URL,"URN:",4))
  537.             return(URN_TYPE_URL);
  538.         break;
  539.       
  540.     }
  541.  
  542.     /* no type match :( */
  543.     return(0);
  544. }
  545.  
  546.  
  547.  
  548. /* from libnet/mkparse.c */
  549. PRIVATE CONST 
  550. int netCharType[256] =
  551. /*    Bit 0        xalpha        -- the alphas
  552. **    Bit 1        xpalpha        -- as xalpha but 
  553. **                             converts spaces to plus and plus to %20
  554. **    Bit 3 ...    path        -- as xalphas but doesn't escape '/'
  555. */
  556.     /*   0 1 2 3 4 5 6 7 8 9 A B C D E F */
  557.     {    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    /* 0x */
  558.          0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    /* 1x */
  559.          0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4,    /* 2x   !"#$%&'()*+,-./     */
  560.          7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,    /* 3x  0123456789:;<=>?     */
  561.          7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,    /* 4x  @ABCDEFGHIJKLMNO  */
  562.          7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7,    /* 5X  PQRSTUVWXYZ[\]^_     */
  563.          0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,    /* 6x  `abcdefghijklmno     */
  564.          7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,    /* 7X  pqrstuvwxyz{\}~    DEL */
  565.          0, };
  566.  
  567. #define IS_OK(C) (netCharType[((unsigned int) (C))] & (mask))
  568.  
  569.  
  570. #define HEX_ESCAPE '%'
  571.  
  572.  
  573. PUBLIC char *
  574. NET_Escape (const char * str, int mask)
  575. {
  576.     register CONST unsigned char *src;
  577.     register unsigned char *dst;
  578.     char        *result;
  579.     int32         extra = 0;
  580.     char        *hexChars = "0123456789ABCDEF";
  581.  
  582.     if(!str)
  583.         return(0);
  584.  
  585.     for(src=((unsigned char *)str); *src; src++)
  586.       {
  587.         if (!IS_OK(*src))
  588.             extra+=2; /* the escape, plus an extra byte for each nibble */
  589.       }
  590.  
  591.     if(!(result = (char *) XP_ALLOC((int32) (src - ((unsigned char *)str)) + extra + 1)))
  592.         return(0);
  593.  
  594.     dst = (unsigned char *) result;
  595.     for(src=((unsigned char *)str); *src; src++)
  596.     if (IS_OK((unsigned char) (*src)))
  597.       {
  598.         *dst++ = *src;
  599.       }
  600.     else if(mask == URL_XPALPHAS && *src == ' ')
  601.       {
  602.         *dst++ = '+'; /* convert spaces to pluses */
  603.       }
  604.     else 
  605.       {
  606.         *dst++ = HEX_ESCAPE;
  607.         *dst++ = hexChars[(*src >> 4) & 0x0f];  /* high nibble */
  608.         *dst++ = hexChars[*src & 0x0f];     /* low nibble */
  609.       }
  610.  
  611.     *dst++ = '\0';     /* tack on eos */
  612.     return result;
  613. }
  614.  
  615.  
  616. /* from libmsg/msgutils.c */
  617. int
  618. msg_GrowBuffer (uint32 desired_size, uint32 element_size, uint32 quantum,
  619.                 char **buffer, uint32 *size)
  620. {
  621.   if (*size <= desired_size)
  622.     {
  623.       char *new_buf;
  624.       uint32 increment = desired_size - *size;
  625.       if (increment < quantum) /* always grow by a minimum of N bytes */
  626.         increment = quantum;
  627.  
  628. #ifdef TESTFORWIN16
  629.       if (((*size + increment) * (element_size / sizeof(char))) >= 64000)
  630.         {
  631.           /* Make sure we don't choke on WIN16 */
  632.           XP_ASSERT(0);
  633.           return MK_OUT_OF_MEMORY;
  634.         }
  635. #endif /* DEBUG */
  636.  
  637.       new_buf = (*buffer
  638.                  ? (char *) XP_REALLOC (*buffer, (*size + increment)
  639.                                         * (element_size / sizeof(char)))
  640.                  : (char *) XP_ALLOC ((*size + increment)
  641.                                       * (element_size / sizeof(char))));
  642.       if (! new_buf)
  643.         return MK_OUT_OF_MEMORY;
  644.       *buffer = new_buf;
  645.       *size += increment;
  646.     }
  647.   return 0;
  648. }
  649.  
  650.  
  651. XP_List * ExternalURLTypeList=0;
  652.  
  653. #define EXTERNAL_TYPE_URL  999  /* a special external URL type */
  654.  
  655. /* check the passed in url to see if it is an
  656.  * external type url
  657.  */
  658. PRIVATE int
  659. net_CheckForExternalURLType(char * url)
  660. {
  661.     XP_List * list_ptr = ExternalURLTypeList;
  662.     char * reg_type;
  663.     int len;
  664.  
  665.     while((reg_type = (char *)XP_ListNextObject(list_ptr)))
  666.       {
  667.         len = XP_STRLEN(reg_type);
  668.         if(!strncasecomp(reg_type, url, len) && url[len] == ':')
  669.           { 
  670.             /* found it */
  671.             return EXTERNAL_TYPE_URL; /* done */ 
  672.           }
  673.       }
  674.  
  675.     return(0);
  676. }
  677.  
  678. /* modifies a url of the form   /foo/../foo1  ->  /foo1
  679.  *
  680.  * it only operates on "file" "ftp" and "http" url's all others are returned
  681.  * unmodified
  682.  *
  683.  * returns the modified passed in URL string
  684.  */
  685. PRIVATE char *
  686. net_ReduceURL (char *url)
  687. {
  688.     int url_type = NET_URL_Type(url);
  689.     char * fwd_ptr;
  690.     char * url_ptr;
  691.     char * path_ptr;
  692.  
  693.     if(!url)
  694.         return(url);
  695.  
  696.     if(url_type == HTTP_TYPE_URL || url_type == FILE_TYPE_URL ||
  697.        url_type == FTP_TYPE_URL ||
  698.        url_type == SECURE_HTTP_TYPE_URL)
  699.       {
  700.  
  701.         /* find the path so we only change that and not the host
  702.          */
  703.         path_ptr = XP_STRCHR(url, '/');
  704.  
  705.         if(!path_ptr)
  706.             return(url);
  707.  
  708.         if(*(path_ptr+1) == '/')
  709.             path_ptr = XP_STRCHR(path_ptr+2, '/');
  710.             
  711.         if(!path_ptr)
  712.             return(url);
  713.  
  714.         fwd_ptr = path_ptr;
  715.         url_ptr = path_ptr;
  716.  
  717.         for(; *fwd_ptr != '\0'; fwd_ptr++)
  718.           {
  719.             
  720.             if(*fwd_ptr == '/' && *(fwd_ptr+1) == '.' && *(fwd_ptr+2) == '/')
  721.               {
  722.                 /* remove ./ 
  723.                  */    
  724.                 fwd_ptr += 1;
  725.               }
  726.             else if(*fwd_ptr == '/' && *(fwd_ptr+1) == '.' && *(fwd_ptr+2) == '.' && 
  727.                                     (*(fwd_ptr+3) == '/' || *(fwd_ptr+3) == '\0'))
  728.               {
  729.                 /* remove foo/.. 
  730.                  */    
  731.                 /* reverse the url_ptr to the previous slash
  732.                  */
  733.                 if(url_ptr != path_ptr) 
  734.                     url_ptr--; /* we must be going back at least one */
  735.                 for(;*url_ptr != '/' && url_ptr != path_ptr; url_ptr--)
  736.                     ;  /* null body */
  737.     
  738.                 /* forward the fwd_prt past the ../
  739.                  */
  740.                 fwd_ptr += 2;
  741.               }
  742.             else
  743.               {
  744.                 /* copy the url incrementaly 
  745.                  */
  746.                 *url_ptr++ = *fwd_ptr;
  747.               }
  748.           }
  749.         *url_ptr = '\0';  /* terminate the url */
  750.       }
  751.  
  752.     return(url);
  753. }
  754.  
  755.  
  756. /* Makes a relative URL into an absolute one.  
  757.  *
  758.  * If an absolute url is passed in it will be copied and returned.
  759.  *
  760.  * Always returns a malloc'd string or NULL on out of memory error
  761.  */
  762. PUBLIC char *
  763. NET_MakeAbsoluteURL(char * absolute_url, char * relative_url)
  764. {
  765.     char * ret_url=0;
  766.     int    new_length;
  767.     char * cat_point=0;
  768.     char   cat_point_char;
  769.     int    url_type=0;
  770.     int    base_type;
  771.  
  772.     /* if either is NULL
  773.      */
  774.     if(!absolute_url || !relative_url)
  775.       {
  776.         StrAllocCopy(ret_url, relative_url);
  777.         return(ret_url);
  778.       }
  779.  
  780.     /* use the URL_Type function to figure
  781.      * out if it's a recognized URL method
  782.      */
  783.     url_type = NET_URL_Type(relative_url);
  784.  
  785.     /* there are some extra cases we need to catch
  786.      */
  787.     if(!url_type)
  788.       {
  789.        switch(*relative_url) 
  790.         {
  791.           case 'i':
  792.             if(!XP_STRNCMP(relative_url,"internal-icon-", 14)
  793.                    || !XP_STRNCMP(relative_url,"internal-external-reconnect:", 28)
  794.                      || !XP_STRCMP(relative_url,"internal-external-plugin"))
  795.             url_type = INTERNAL_IMAGE_TYPE_URL;
  796.             break;
  797.           case '/':
  798.             if(!strncasecomp(relative_url, "/mc-icons/", 10) ||
  799.                !strncasecomp(relative_url, "/ns-icons/", 10))
  800.                 {
  801.                 if(!XP_STRCMP(relative_url+10, "menu.gif"))
  802.                     url_type = INTERNAL_IMAGE_TYPE_URL;
  803.                 else if(!XP_STRCMP(relative_url+10, "unknown.gif"))
  804.                     url_type = INTERNAL_IMAGE_TYPE_URL;
  805.                 else if(!XP_STRCMP(relative_url+10, "text.gif"))
  806.                     url_type = INTERNAL_IMAGE_TYPE_URL;
  807.                 else if(!XP_STRCMP(relative_url+10, "image.gif"))
  808.                     url_type = INTERNAL_IMAGE_TYPE_URL;
  809.                 else if(!XP_STRCMP(relative_url+10, "sound.gif"))
  810.                     url_type = INTERNAL_IMAGE_TYPE_URL;
  811.                 else if(!XP_STRCMP(relative_url+10, "binary.gif"))
  812.                     url_type = INTERNAL_IMAGE_TYPE_URL;
  813.                 else if(!XP_STRCMP(relative_url+10, "movie.gif"))
  814.                     url_type = INTERNAL_IMAGE_TYPE_URL;
  815.                 }
  816.             break;
  817.         }
  818.       }
  819.     else if(url_type == ABOUT_TYPE_URL)
  820.       {
  821.         /* don't allow about:cache in a document */
  822.         if(!strncasecomp(relative_url, "about:cache", 11)
  823.            || !strncasecomp(relative_url, "about:global", 12)
  824.            || !strncasecomp(relative_url, "about:image-cache", 17)
  825.            || !strncasecomp(relative_url, "about:memory-cache", 18))
  826.           {
  827.             return XP_STRDUP("");
  828.           }
  829.       }
  830.  
  831.     if(!url_type)
  832.         url_type = net_CheckForExternalURLType(relative_url);
  833.  
  834.     if(url_type)
  835.       {
  836.         /* it's either an absolute url
  837.          * or a messed up one of the type proto:/path
  838.          * but notice the missing host.
  839.          */
  840.         char * colon = XP_STRCHR(relative_url, ':'); /* must be there */
  841.  
  842.         if( (colon && *(colon+1) == '/' && *(colon+2) == '/') || 
  843.             (url_type != GOPHER_TYPE_URL
  844.              && url_type != FTP_TYPE_URL
  845.               && url_type != HTTP_TYPE_URL
  846.              && url_type != SECURE_HTTP_TYPE_URL
  847.              && url_type != RLOGIN_TYPE_URL
  848.              && url_type != TELNET_TYPE_URL
  849.              && url_type != TN3270_TYPE_URL
  850.              && url_type != WAIS_TYPE_URL) )
  851.           {
  852.             /* it appears to have all it's parts.  Assume it's completely
  853.              * absolute
  854.              */
  855.             StrAllocCopy(ret_url, relative_url);
  856.             return(ret_url);
  857.           }
  858.         else
  859.           {
  860.             /* it's a screwed up relative url of the form http:[relative url]
  861.              * remove the stuff before and at the colon and treat it as a normal
  862.              * relative url
  863.              */
  864.             char * colon = XP_STRCHR(relative_url, ':');
  865.  
  866.             relative_url = colon+1;
  867.           }
  868.       }
  869.  
  870.  
  871.     /* At this point, we know that `relative_url' is not absolute.
  872.        If the base URL, `absolute_url', is a "mailbox:" URL, then
  873.        we should not allow relative expansion: that is,
  874.        NET_MakeAbsoluteURL("mailbox:/A/B/C", "YYY") should not
  875.        return "mailbox:/A/B/YYY".
  876.  
  877.        However, expansion of "#" and "?" parameters should work:
  878.        NET_MakeAbsoluteURL("mailbox:/A/B/C?id=XXX", "#part2")
  879.        should be allowed to expand to "mailbox:/A/B/C?id=XXX#part2".
  880.  
  881.        If you allow random HREFs in attached HTML to mail messages to
  882.        expand to mailbox URLs, then bad things happen -- among other
  883.        things, an entry will be automatically created in the folders
  884.        list for each of these bogus non-files.
  885.  
  886.        It's an open question as to whether relative expansion should
  887.        be allowed for news: and snews: URLs.
  888.  
  889.        Reasons to allow it:
  890.  
  891.          =  ClariNet has been using it
  892.  
  893.          =  (Their reason:) it's the only way for an HTML news message
  894.             to refer to another HTML news message in a way which
  895.             doesn't make assumptions about the name of the news host,
  896.             and which also doesn't assume that the message is on the
  897.             default news host.
  898.  
  899.        Reasons to disallow it:
  900.  
  901.          =  Consistency with "mailbox:"
  902.  
  903.          =  If there is a news message which has type text/html, and
  904.             which has a relative URL like <IMG SRC="foo.gif"> in it,
  905.             but which has no <BASE> tag, then we would expand that
  906.             image to "news:foo.gif".  Which would fail, of course,
  907.             but which might annoy news admins by generating bogus
  908.             references.
  909.  
  910.        So for now, let's allow 
  911.        NET_MakeAbsoluteURL("news:123@4", "456@7") => "news:456@7"; and
  912.        NET_MakeAbsoluteURL("news://h/123@4", "456@7") => "news://h/456@7".
  913.      */
  914.     base_type = NET_URL_Type(absolute_url);
  915.     if (base_type == MAILBOX_TYPE_URL &&
  916.         *relative_url != '#' &&
  917.         *relative_url != '?')
  918.       {
  919.         return XP_STRDUP("");
  920.       }
  921.  
  922.     if(relative_url[0] == '/' && relative_url[1] == '/')
  923.       {
  924.         /* a host absolute URL
  925.          */
  926.  
  927.         /* find the colon after the protocol
  928.          */
  929.         cat_point = XP_STRCHR(absolute_url, ':');
  930.         if (cat_point && base_type == WYSIWYG_TYPE_URL)
  931.             cat_point = XP_STRCHR(cat_point + 1, ':');
  932.  
  933.         /* append after the colon
  934.          */
  935.         if(cat_point)
  936.            cat_point++;
  937.  
  938.       }
  939.     else if(relative_url[0] == '/')
  940.       {
  941.         /* a path absolute URL
  942.          * append at the slash after the host part
  943.          */
  944.  
  945.         /* find the colon after the protocol 
  946.          */
  947.         char *colon = XP_STRCHR(absolute_url, ':');
  948.         if (colon && base_type == WYSIWYG_TYPE_URL)
  949.             colon = XP_STRCHR(colon + 1, ':');
  950.  
  951.         if(colon)
  952.           {
  953.             if(colon[1] == '/' && colon[2] == '/')
  954.               {
  955.                 /* find the next slash 
  956.                  */
  957.                 cat_point = XP_STRCHR(colon+3, '/');
  958.  
  959.                 if(!cat_point)
  960.                   {
  961.                     /* if there isn't another slash then the cat point is the very end
  962.                      */
  963.                     cat_point = &absolute_url[XP_STRLEN(absolute_url)];
  964.                   }
  965.               }
  966.             else
  967.               {
  968.                 /* no host was given so the cat_point is right after the colon
  969.                  */
  970.                 cat_point = colon+1;
  971.               }
  972.  
  973. #if defined(XP_WIN) || defined(XP_OS2)
  974.             /* this will allow drive letters to work right on windows 
  975.              */
  976.             if(XP_IS_ALPHA(*cat_point) && *(cat_point+1) == ':')
  977.                 cat_point += 2;
  978. #endif /* XP_WIN */
  979.  
  980.           }
  981.       }
  982.     else if(relative_url[0] == '#')
  983.       {
  984.         /* a positioning within the same document relative url
  985.          *
  986.          * add teh relative url to the full text of the absolute url minus
  987.          * any # punctuation the url might have
  988.           *
  989.          */
  990.         char * hash = XP_STRCHR(absolute_url, '#');
  991.     
  992.         if(hash)
  993.           {
  994.             char * ques_mark = XP_STRCHR(absolute_url, '?');
  995.    
  996.             if(ques_mark)
  997.               {
  998.                 /* this is a hack.
  999.                  * copy things to try and make them more correct
  1000.                  */
  1001.                 *hash = '\0';
  1002.  
  1003.                 StrAllocCopy(ret_url, absolute_url);
  1004.                 StrAllocCat(ret_url, relative_url);
  1005.                 StrAllocCat(ret_url, ques_mark);
  1006.  
  1007.                 *hash = '#';
  1008.                 
  1009.                 return(net_ReduceURL(ret_url));
  1010.               }
  1011.  
  1012.             cat_point = hash;
  1013.           }
  1014.         else
  1015.           {
  1016.             cat_point = &absolute_url[XP_STRLEN(absolute_url)]; /* the end of the URL */
  1017.           }
  1018.       }
  1019.     else
  1020.       {
  1021.         /* a completely relative URL
  1022.          *
  1023.          * append after the last slash
  1024.          */
  1025.         char * ques = XP_STRCHR(absolute_url, '?');
  1026.         char * hash = XP_STRCHR(absolute_url, '#');
  1027.  
  1028.         if(ques)
  1029.             *ques = '\0';
  1030.  
  1031.         if(hash)
  1032.             *hash = '\0';
  1033.  
  1034.         cat_point = XP_STRRCHR(absolute_url, '/');
  1035.  
  1036.         /* if there are no slashes then append right after the colon after the protocol
  1037.          */
  1038.         if(!cat_point)
  1039.             cat_point = XP_STRCHR(absolute_url, ':');
  1040.  
  1041.         /* set the value back 
  1042.          */
  1043.         if(ques)
  1044.             *ques = '?';
  1045.  
  1046.         if(hash)
  1047.             *hash = '#';
  1048.  
  1049.         if(cat_point)
  1050.             cat_point++;  /* append right after the slash or colon not on it */
  1051.       }
  1052.     
  1053.     if(cat_point)
  1054.       {
  1055.         cat_point_char = *cat_point;  /* save the value */
  1056.         *cat_point = '\0';
  1057.         new_length = XP_STRLEN(absolute_url) + XP_STRLEN(relative_url) + 1;
  1058.         ret_url = (char *) XP_ALLOC(new_length);
  1059.         if(!ret_url)
  1060.             return(NULL);  /* out of memory */
  1061.  
  1062.         XP_STRCPY(ret_url, absolute_url);
  1063.         XP_STRCAT(ret_url, relative_url);
  1064.         *cat_point = cat_point_char;  /* set the absolute url back to its original state */
  1065.       } 
  1066.     else
  1067.       {
  1068.         /* something went wrong.  just return a copy of the relative url
  1069.          */
  1070.         StrAllocCopy(ret_url, relative_url);
  1071.       }
  1072.  
  1073.     return(net_ReduceURL(ret_url));
  1074. }
  1075.  
  1076.  
  1077. /* from libmsg/msgutils.c */
  1078. static int
  1079. msg_convert_and_send_buffer(char* buf, int length, XP_Bool convert_newlines_p,
  1080.                             int32 (*per_line_fn) (char *line,
  1081.                                                   uint32 line_length,
  1082.                                                   void *closure),
  1083.                             void *closure)
  1084. {
  1085.   /* Convert the line terminator to the native form.
  1086.    */
  1087.   char* newline;
  1088.  
  1089.   XP_ASSERT(buf && length > 0);
  1090.   if (!buf || length <= 0) return -1;
  1091.   newline = buf + length;
  1092.   XP_ASSERT(newline[-1] == CR || newline[-1] == LF);
  1093.   if (newline[-1] != CR && newline[-1] != LF) return -1;
  1094.  
  1095.   if (!convert_newlines_p)
  1096.     {
  1097.     }
  1098. #if (LINEBREAK_LEN == 1)
  1099.   else if ((newline - buf) >= 2 &&
  1100.            newline[-2] == CR &&
  1101.            newline[-1] == LF)
  1102.     {
  1103.       /* CRLF -> CR or LF */
  1104.       buf [length - 2] = LINEBREAK[0];
  1105.       length--;
  1106.     }
  1107.   else if (newline > buf + 1 &&
  1108.            newline[-1] != LINEBREAK[0])
  1109.     {
  1110.       /* CR -> LF or LF -> CR */
  1111.       buf [length - 1] = LINEBREAK[0];
  1112.     }
  1113. #else
  1114.   else if (((newline - buf) >= 2 && newline[-2] != CR) ||
  1115.            ((newline - buf) >= 1 && newline[-1] != LF))
  1116.     {
  1117.       /* LF -> CRLF or CR -> CRLF */
  1118.       length++;
  1119.       buf[length - 2] = LINEBREAK[0];
  1120.       buf[length - 1] = LINEBREAK[1];
  1121.     }
  1122. #endif
  1123.  
  1124.   return (*per_line_fn)(buf, length, closure);
  1125. }
  1126.  
  1127.  
  1128. /* from libmsg/msgutils.c */
  1129. int
  1130. msg_LineBuffer (const char *net_buffer, int32 net_buffer_size,
  1131.                 char **bufferP, uint32 *buffer_sizeP, uint32 *buffer_fpP,
  1132.                 XP_Bool convert_newlines_p,
  1133.                 int32 (*per_line_fn) (char *line, uint32 line_length,
  1134.                                       void *closure),
  1135.                 void *closure)
  1136. {
  1137.   int status = 0;
  1138.   if (*buffer_fpP > 0 && *bufferP && (*bufferP)[*buffer_fpP - 1] == CR &&
  1139.       net_buffer_size > 0 && net_buffer[0] != LF) {
  1140.     /* The last buffer ended with a CR.  The new buffer does not start
  1141.        with a LF.  This old buffer should be shipped out and discarded. */
  1142.     XP_ASSERT(*buffer_sizeP > *buffer_fpP);
  1143.     if (*buffer_sizeP <= *buffer_fpP) return -1;
  1144.     status = msg_convert_and_send_buffer(*bufferP, *buffer_fpP,
  1145.                                          convert_newlines_p,
  1146.                                          per_line_fn, closure);
  1147.     if (status < 0) return status;
  1148.     *buffer_fpP = 0;
  1149.   }
  1150.   while (net_buffer_size > 0)
  1151.     {
  1152.       const char *net_buffer_end = net_buffer + net_buffer_size;
  1153.       const char *newline = 0;
  1154.       const char *s;
  1155.  
  1156.  
  1157.       for (s = net_buffer; s < net_buffer_end; s++)
  1158.         {
  1159.           /* Move forward in the buffer until the first newline.
  1160.              Stop when we see CRLF, CR, or LF, or the end of the buffer.
  1161.              *But*, if we see a lone CR at the *very end* of the buffer,
  1162.              treat this as if we had reached the end of the buffer without
  1163.              seeing a line terminator.  This is to catch the case of the
  1164.              buffers splitting a CRLF pair, as in "FOO\r\nBAR\r" "\nBAZ\r\n".
  1165.            */
  1166.           if (*s == CR || *s == LF)
  1167.             {
  1168.               newline = s;
  1169.               if (newline[0] == CR)
  1170.                 {
  1171.                   if (s == net_buffer_end - 1)
  1172.                     {
  1173.                       /* CR at end - wait for the next character. */
  1174.                       newline = 0;
  1175.                       break;
  1176.                     }
  1177.                   else if (newline[1] == LF)
  1178.                     /* CRLF seen; swallow both. */
  1179.                     newline++;
  1180.                 }
  1181.               newline++;
  1182.               break;
  1183.             }
  1184.         }
  1185.  
  1186.       /* Ensure room in the net_buffer and append some or all of the current
  1187.          chunk of data to it. */
  1188.       {
  1189.         const char *end = (newline ? newline : net_buffer_end);
  1190.         uint32 desired_size = (end - net_buffer) + (*buffer_fpP) + 1;
  1191.  
  1192.         if (desired_size >= (*buffer_sizeP))
  1193.           {
  1194.             status = msg_GrowBuffer (desired_size, sizeof(char), 1024,
  1195.                                      bufferP, buffer_sizeP);
  1196.             if (status < 0) return status;
  1197.           }
  1198.         XP_MEMCPY ((*bufferP) + (*buffer_fpP), net_buffer, (end - net_buffer));
  1199.         (*buffer_fpP) += (end - net_buffer);
  1200.       }
  1201.  
  1202.       /* Now *bufferP contains either a complete line, or as complete
  1203.          a line as we have read so far.
  1204.  
  1205.          If we have a line, process it, and then remove it from `*bufferP'.
  1206.          Then go around the loop again, until we drain the incoming data.
  1207.        */
  1208.       if (!newline)
  1209.         return 0;
  1210.  
  1211.       status = msg_convert_and_send_buffer(*bufferP, *buffer_fpP,
  1212.                                            convert_newlines_p,
  1213.                                            per_line_fn, closure);
  1214.       if (status < 0) return status;
  1215.  
  1216.       net_buffer_size -= (newline - net_buffer);
  1217.       net_buffer = newline;
  1218.       (*buffer_fpP) = 0;
  1219.     }
  1220.   return 0;
  1221. }
  1222.