home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libnet / mkutils.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  89.0 KB  |  3,372 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.  *
  20.  * Implemented by Lou Montulli '94-'98
  21.  *
  22.  * this is the dumping grounds for random Netlib functions
  23.  * Home for utility functions and anything else that 
  24.  * doesn't fit elsewhere.
  25.  */
  26.  
  27. #include "rosetta.h"
  28. #include "mkutils.h"
  29. #include "gui.h"
  30. #include "mknews.h"
  31. #include "mkparse.h"
  32. #include "mkaccess.h"
  33. #include "libi18n.h"
  34. #include "msgcom.h"
  35. #include "mkcache.h"
  36. #include "mkextcac.h"
  37. #include "mime.h"
  38. #include "secrng.h"
  39. #include "ssl.h"
  40. #include "prefapi.h"
  41. #include "secnav.h"
  42. #include "preenc.h"
  43. #include "mkselect.h"
  44.  
  45. #include "xp_error.h"
  46. #include "xpgetstr.h"
  47.  
  48. #include "mimeenc.h"
  49. #include "intl_csi.h"
  50.  
  51. #ifdef XP_MAC
  52. #include "MacBinSupport.h"
  53. #endif
  54.  
  55. typedef struct {
  56.   char *buffer;
  57.   int32 size;
  58.   int32 pos;
  59. } BufferStruct;
  60.  
  61. #ifndef MAX
  62. #define MAX(x, y)    (((x) > (y)) ? (x) : (y))
  63. #endif
  64.  
  65. static int
  66. net_buffer_output_fn ( const char *buf, int32 size, void *closure);
  67.  
  68. extern int MK_OUT_OF_MEMORY;
  69. extern int MK_UNABLE_TO_LOCATE_FILE;
  70. extern int XP_ERRNO_EWOULDBLOCK;
  71. extern int MK_TCP_WRITE_ERROR;
  72. extern int XP_ERRNO_EALREADY;
  73. extern int XP_ALERT_URN_USEHTTP;
  74. extern int XP_ALERT_NFS_USEHTTP;
  75. extern int MK_NO_WAIS_PROXY;
  76.  
  77. /* print network progress to the front end
  78.  */
  79. MODULE_PRIVATE void
  80. NET_Progress(MWContext *context, char *msg)
  81. {
  82.     FE_Progress(context, msg);
  83. }
  84.  
  85. /* note:  on the Macintosh local_dir_name will be in the following format: */
  86. /*              file:///Hard%20Disk/Folder%20Name/File.html                */
  87. PUBLIC char **
  88. NET_AssembleAllFilesInDirectory(MWContext *context, char * local_dir_name)
  89. {
  90.     XP_Dir dir_ptr;
  91.     XP_DirEntryStruct *dir_entry;
  92.     XP_StatStruct stat_entry;
  93.     char **files_to_post;
  94.     char *file_to_post = 0;
  95.     int32 i, cur_array_size;
  96.     int end;
  97.     Bool have_slash;
  98. #define    INITIAL_ARRAY_SIZE 10
  99. #define EXPAND_ARRAY_BY 5
  100.  
  101.     XP_ASSERT(local_dir_name);
  102.  
  103. #ifdef XP_MAC
  104.     local_dir_name += 7;    // chop-off "file://"
  105. #endif
  106.  
  107.     if(NULL == (dir_ptr = XP_OpenDir(local_dir_name, xpFileToPost)))
  108.       {
  109.           FE_Alert(context, "Unable to open local directory");
  110.           return NULL;
  111.       }
  112.  
  113.     /* make sure local_dir_name doesn't have a slash at the end */
  114.     end = XP_STRLEN(local_dir_name)-1;
  115.     have_slash = (local_dir_name[end] == '/') || (local_dir_name[end] == '\\');
  116.  
  117.     files_to_post = (char**) XP_ALLOC(INITIAL_ARRAY_SIZE * sizeof(char*));
  118.     if(!files_to_post)
  119.         return NULL;
  120.     cur_array_size = INITIAL_ARRAY_SIZE;
  121.  
  122.     i=0;
  123.     while((dir_entry = XP_ReadDir(dir_ptr)) != NULL)
  124.       {
  125.           /* skip . and .. */
  126.         if(!XP_STRCMP(dir_entry->d_name, ".") || !XP_STRCMP(dir_entry->d_name, ".."))
  127.             continue;
  128.         
  129.         /* assemble full pathname first so we can test if its a directory */
  130.         file_to_post = XP_STRDUP(local_dir_name);
  131.         if ( ! file_to_post ){
  132.             return NULL;
  133.         }
  134.  
  135.         /* Append slash to directory if we don't already have one */
  136.         if( !have_slash )
  137.           {
  138. #ifdef XP_WIN
  139.             StrAllocCat(file_to_post, "\\");
  140. #else
  141.             StrAllocCat(file_to_post, "/");
  142. #endif
  143.           }
  144.         if ( ! file_to_post )
  145.           {
  146.             return NULL;
  147.           }
  148.  
  149.         StrAllocCat(file_to_post, dir_entry->d_name);
  150.         if ( ! file_to_post )
  151.           {
  152.             return NULL;
  153.           }
  154.  
  155.         /* skip over subdirectory names */
  156.         if(-1 != XP_Stat(file_to_post, &stat_entry, xpFileToPost) && S_ISDIR(stat_entry.st_mode) )
  157.           {
  158.             XP_FREE(file_to_post);
  159.             continue;
  160.           }
  161.  
  162.         /* expand array if necessary 
  163.          * always leave room for the NULL terminator */
  164.         if(i >= cur_array_size-1)
  165.           {
  166.               files_to_post = (char**) XP_REALLOC(files_to_post, (cur_array_size + EXPAND_ARRAY_BY) * sizeof(char*)); 
  167.             if(!files_to_post)
  168.                 return NULL;
  169.             cur_array_size += EXPAND_ARRAY_BY;
  170.           }
  171.  
  172.         files_to_post[i++] = XP_STRDUP(file_to_post);
  173.  
  174.         XP_FREE(file_to_post);
  175.        }
  176.  
  177.     /* NULL terminate the array, space is guarenteed above */
  178.     files_to_post[i] = NULL;
  179.  
  180.     return(files_to_post);
  181. }
  182.  
  183. /********KILL this, use NET_PublishFilesTo ************/
  184. /* upload a set of local files (array of char*)
  185.  * all files must have full path name
  186.  * first file is primary html document,
  187.  * others are included images or other files
  188.  * in the same directory as main file
  189.  */
  190. PUBLIC void
  191. NET_PublishFiles(MWContext *context, 
  192.                  char **files_to_publish,
  193.                  char *remote_directory)
  194. {
  195.     URL_Struct *URL_s;       
  196.  
  197.     XP_ASSERT(context && files_to_publish && remote_directory);
  198.     if(!context || !files_to_publish || !*files_to_publish || !remote_directory)
  199.         return;
  200.  
  201.     /* create a URL struct */
  202.     URL_s = NET_CreateURLStruct(remote_directory, NET_SUPER_RELOAD);
  203.     if(!URL_s)
  204.       {    
  205.         FE_Alert(context, "Error: not enough memory for file upload");
  206.           return;  /* does not exist */
  207.       }
  208.  
  209.     FREE_AND_CLEAR(URL_s->content_type);
  210.  
  211.     /* add the files that we are posting and set the method to POST */
  212.     URL_s->files_to_post = files_to_publish;
  213.     URL_s->method = URL_POST_METHOD;
  214.     
  215.     /* start the load */
  216.     FE_GetURL(context, URL_s);
  217. }
  218.  
  219. /* upload a set of local files (array of char*)
  220.  * first file is primary html document,
  221.  * others are included images or other files. 
  222.  *
  223.  * It is legal to pass in NULL as the value of publish_to.  This will duplicate
  224.     the functionality of the old NET_PublishFiles. 
  225.  * files_to_publish and publish_to are used by and will be freed by NET_PublishFilesTo, 
  226.  * base_url is copied */
  227. PUBLIC void
  228. NET_PublishFilesTo(MWContext *context, 
  229.                  char **files_to_publish,
  230.                  char **publish_to,  /* Absolute URLs of the location to 
  231.                                                * publish the files to. Used only if HTTP.  
  232.                                                * Ignored if FTP (except to delete memory.)*/
  233.                  XP_Bool *add_crlf, /* For each file in files_to_publish, should every line 
  234.                                        end in a CRLF. */
  235.                  char *base_url, /* Directory to publish to, or the destination 
  236.                                            * URL of the root HTML document. */
  237.                  char *username,
  238.                  char *password,
  239.                  Net_GetUrlExitFunc *exit_func,
  240.                  void *fe_data)
  241. {
  242.   URL_Struct *URL_s;       
  243.  
  244.   if(!context || !files_to_publish || !*files_to_publish || !base_url) {
  245.     XP_ASSERT(0);
  246.     return;
  247.   }
  248.     
  249.     /* create a URL struct */
  250.   URL_s = NET_CreateURLStruct(base_url, NET_SUPER_RELOAD);
  251.     if(!URL_s)
  252.   {    
  253.     FE_Alert(context, "Error: not enough memory for file upload");
  254.     return;  /* does not exist */
  255.   }
  256.  
  257.   if (username)
  258.     URL_s->username = XP_STRDUP(username);
  259.   if (password)
  260.     URL_s->password = XP_STRDUP(password);
  261.  
  262.   FREE_AND_CLEAR(URL_s->content_type);
  263.  
  264.     /* add the files that we are posting and set the method to POST */
  265.   URL_s->files_to_post = files_to_publish;
  266.   URL_s->post_to = publish_to;
  267.   URL_s->add_crlf = add_crlf;
  268.   URL_s->method = URL_POST_METHOD;
  269.   URL_s->pre_exit_fn = exit_func; /* May be NULL */
  270.   URL_s->fe_data = fe_data;
  271.    
  272.     /* start the load */
  273.   FE_GetURL(context, URL_s);
  274. }
  275.  
  276. /* assemble username, password, and ftp:// or http:// URL into
  277.  * ftp://user:password@/blah  format for uploading
  278. */
  279. PUBLIC Bool
  280. NET_MakeUploadURL( char **full_location, char *location, 
  281.                    char *user_name, char *password )
  282. {
  283.     char *start;
  284.     char *pSrc;
  285.     char *destination;
  286.     char *at_ptr;
  287.     int iSize;
  288.  
  289.     if( !full_location || !location ) return FALSE;
  290.     if( *full_location ) XP_FREE(*full_location);
  291.  
  292.     iSize = strlen(location) + 4;
  293.     if( user_name ) iSize += strlen(user_name);
  294.     if( password ) iSize += strlen(password);
  295.  
  296.     *full_location = (char*)XP_ALLOC(iSize);
  297.     if( !*full_location ){
  298.         /* Return an empty string */
  299.         *full_location = strdup("");
  300.         return FALSE;
  301.     }
  302.     **full_location = '\0';
  303.  
  304.     /* Find start just past http:// or ftp:// */
  305.     start = XP_STRSTR(location, "//");
  306.     if( !start ) return FALSE;
  307.  
  308.     /* Point to just past the host part */
  309.     start += 2;
  310.     pSrc = location;
  311.     destination = *full_location;
  312.     /* Copy up to and including "//" */
  313.     while( pSrc < start ) *destination++ = *pSrc++;
  314.     *destination = '\0';
  315.  
  316.     /* Skip over any user:password in supplied location */
  317.     at_ptr = XP_STRCHR(start, '@');
  318.     if( at_ptr ){
  319.         start = at_ptr + 1;
  320.     }
  321.     /* Append supplied "user:password@"
  322.      * (This can be used without password)
  323.     */
  324.     if( user_name && XP_STRLEN(user_name) > 0 ){
  325.         XP_STRCAT(*full_location, user_name);
  326.         if ( password  && XP_STRLEN(password) > 0 ){
  327.             XP_STRCAT(*full_location,":");
  328.             XP_STRCAT(*full_location, password);
  329.         }
  330.         XP_STRCAT(*full_location, "@");
  331.     }
  332.     /* Append the rest of location */
  333.     XP_STRCAT(*full_location, start);
  334.  
  335.     return TRUE;
  336. }
  337.  
  338. /* extract the username, password, and reassembled location string 
  339.  * from an ftp:// or http:// URL
  340. */
  341. PUBLIC Bool
  342. NET_ParseUploadURL( char *full_location, char **location, 
  343.                     char **user_name, char **password )
  344. {
  345.     char *start;
  346.     char *skip_dest;
  347.     char *at_ptr;
  348.     char *colon_ptr;
  349.     char at;
  350.     char colon;
  351.  
  352.     if( !full_location || !location ) return FALSE;
  353.  
  354.     /* Empty exitisting strings... */   
  355.     if(*location) XP_FREE(*location);
  356.     if( user_name && *user_name) XP_FREE(*user_name);
  357.     if( password && *password) XP_FREE(*password);
  358.  
  359.     /* Find start just past http:// or ftp://  */
  360.     start = XP_STRSTR(full_location, "//");
  361.     if( !start ) return FALSE;
  362.  
  363.     /* Point to just past the host part */
  364.     start += 2;
  365.     
  366.     /* Start by simply copying full location
  367.      * (may waste some bytes, but much simpler!)
  368.     */
  369.     *location = XP_STRDUP(full_location);
  370.     if( !*location ) return FALSE;
  371.  
  372.     /* Destination to append location without
  373.      *  user:password is same place copied string
  374.     */
  375.     skip_dest = *location + (start - full_location);
  376.  
  377.     /* Skip over any user:password in supplied location
  378.      *  while copying those to other strings
  379.     */
  380.     at_ptr = XP_STRCHR(start, '@');
  381.     colon_ptr = XP_STRCHR(start, ':');
  382.  
  383.     if( at_ptr ){
  384.         /* save character */
  385.         at = *at_ptr;
  386.  
  387.         /* Copy part past the @ over previously-copied full string */
  388.         XP_STRCPY(skip_dest, (at_ptr + 1));
  389.         
  390.         /* Terminate for the password (or user) string */
  391.         *at_ptr = '\0';
  392.         if( colon_ptr ){
  393.             /* save character */
  394.             colon = *colon_ptr;
  395.  
  396.             if( password ){
  397.                 *password = XP_STRDUP((colon_ptr+1));
  398.             }
  399.             /* terminate for the user string */
  400.             *colon_ptr = '\0';
  401.         } else if( password ) {
  402.             *password = XP_STRDUP("");
  403.         }
  404.         if( user_name ){
  405.             *user_name = XP_STRDUP(start);
  406.         }
  407.         /* restore characters */
  408.         *at_ptr = at;
  409.         if( colon_ptr ) *colon_ptr = colon;
  410.  
  411.     } else {
  412.         /* Supply empty strings for these */
  413.         if( user_name ){
  414.             *user_name = XP_STRDUP("");
  415.         }
  416.         if( password ){
  417.             *password = XP_STRDUP("");
  418.         }
  419.     }
  420.     return TRUE;
  421. }
  422.  
  423.  
  424. /* returns a malloc'd string containing a unique id 
  425.  * generated from the sec random stuff.
  426.  */
  427. PUBLIC char * 
  428. NET_GetUniqueIdString(void)
  429. {
  430. #define BYTES_OF_RANDOMNESS 20
  431.     char rand_buf[BYTES_OF_RANDOMNESS+10]; 
  432.     char *rv=0;
  433.  
  434.  
  435.     RNG_GenerateGlobalRandomBytes(rand_buf, BYTES_OF_RANDOMNESS);
  436.  
  437.     /* now uuencode it so it goes across the wire right */
  438.     rv = (char *) XP_ALLOC((BYTES_OF_RANDOMNESS * (4/3)) + 10);
  439.      
  440.     if(rv)
  441.         NET_UUEncode((unsigned char *)rand_buf, (unsigned char *)rv, BYTES_OF_RANDOMNESS);
  442.  
  443.     return(rv);
  444.  
  445. #undef BYTES_OF_RANDOMNESS
  446. }
  447.  
  448.  
  449. /* The magic set of 64 chars in the uuencoded data */
  450. PRIVATE unsigned char uuset[] = {
  451. 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+'
  452. ,'/' };
  453.  
  454. MODULE_PRIVATE int
  455. NET_UUEncode(unsigned char *src, unsigned char *dst, int srclen)
  456. {
  457.    int  i, r;
  458.    unsigned char *p;
  459.  
  460. /* To uuencode, we snip 8 bits from 3 bytes and store them as
  461. 6 bits in 4 bytes.   6*4 == 8*3 (get it?) and 6 bits per byte
  462. yields nice clean bytes
  463.  
  464. It goes like this:
  465.     AAAAAAAA BBBBBBBB CCCCCCCC
  466. turns into the standard set of uuencode ascii chars indexed by numbers:
  467.     00AAAAAA 00AABBBB 00BBBBCC 00CCCCCC
  468.  
  469. Snip-n-shift, snip-n-shift, etc....
  470.  
  471. */
  472.  
  473.    for (p=dst,i=0; i < srclen; i += 3) {
  474.         /* Do 3 bytes of src */
  475.         register char b0, b1, b2;
  476.  
  477.         b0 = src[0];
  478.         if (i==srclen-1)
  479.             b1 = b2 = '\0';
  480.         else if (i==srclen-2) {
  481.             b1 = src[1];
  482.             b2 = '\0';
  483.         }
  484.         else {
  485.             b1 = src[1];
  486.             b2 = src[2];
  487.         }
  488.  
  489.         *p++ = uuset[b0>>2];
  490.         *p++ = uuset[(((b0 & 0x03) << 4) | ((b1 & 0xf0) >> 4))];
  491.         *p++ = uuset[(((b1 & 0x0f) << 2) | ((b2 & 0xc0) >> 6))];
  492.         *p++ = uuset[b2 & 0x3f];
  493.         src += 3;
  494.    }
  495.    *p = 0;      /* terminate the string */
  496.    r = (unsigned char *)p - (unsigned char *)dst;       /* remember how many we
  497. did */
  498.  
  499.    /* Always do 4-for-3, but if not round threesome, have to go
  500.       clean up the last extra bytes */
  501.  
  502.    for( ; i != srclen; i--)
  503.         *--p = '=';
  504.  
  505.    return r;
  506. }
  507.  
  508.  
  509. PRIVATE char *
  510. NET_RemoveQuotes(char * string)
  511. {
  512.     char *rv;
  513.     char *end;
  514.  
  515.     rv = XP_StripLine(string);
  516.  
  517.     if(*rv == '"' || *rv == '\'') 
  518.         rv++;
  519.  
  520.     end = &rv[XP_STRLEN(rv)-1];
  521.  
  522.     if(*end == '"' || *end == '\'')
  523.         *end = '\0';
  524.  
  525.     return(rv); }
  526.  
  527. #define POST_DATA_BUFFER_SIZE 2048
  528.  
  529. struct WritePostDataData {
  530.     char    *buffer;
  531.     XP_Bool  last_line_was_complete;
  532.     int32    amt_in_buffer;
  533.     int32    amt_sent;
  534.     int32    total_amt_sent;
  535.     int32    file_size;
  536.     XP_File  fp;
  537.     int32    headerSize;
  538.     int32    headerAmountSent;
  539.     XP_Bool CRSent;
  540.     XP_Bool LFSent;
  541. };
  542.  
  543. PUBLIC void
  544. NET_free_write_post_data_object(struct WritePostDataData *obj)
  545. {
  546.     XP_ASSERT(obj);
  547.  
  548.     if(!obj)
  549.         return;
  550.  
  551.     if (obj->fp)
  552.         XP_FileClose(obj->fp);
  553.  
  554.     FREEIF(obj->buffer);
  555.     FREE(obj);
  556. }
  557.  
  558. /* returns whether or not the socket error was expected. If it was not, all the write post data 
  559.    object was free'd, and the url_s->error_msg was set */
  560. PRIVATE XP_Bool
  561. net_expected_error(URL_Struct *URL_s, struct WritePostDataData **data_obj)
  562. {
  563.     int err = PR_GetError();
  564.     if(err == PR_WOULD_BLOCK_ERROR || err == PR_IS_CONNECTED_ERROR)
  565.         return TRUE;
  566.     URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_WRITE_ERROR, err);
  567.     NET_free_write_post_data_object(*data_obj);
  568.     *data_obj = NULL;
  569.     return FALSE;
  570. }
  571.  
  572. /* this function is called repeatably to write
  573.  * the post data body and headers onto the network.
  574.  *
  575.  * Returns negative on fatal error
  576.  * Returns zero when done
  577.  * Returns positive if not yet completed
  578.  */
  579. PUBLIC int
  580. NET_WritePostData(MWContext  *context,
  581.                   URL_Struct *URL_s,
  582.                   PRFileDesc   *sock,
  583.                   void      **write_post_data_data,
  584.                   XP_Bool     add_crlf_to_line_endings)
  585. {
  586.     struct WritePostDataData *data_obj = (struct WritePostDataData *) 
  587.                                                         *write_post_data_data;
  588.  
  589.     /* init the data object */
  590.     if(!data_obj)
  591.       {
  592.         data_obj = XP_NEW(struct WritePostDataData);
  593.         *write_post_data_data = data_obj;
  594.  
  595.         if(!data_obj)
  596.             return(MK_OUT_OF_MEMORY);
  597.  
  598.         XP_MEMSET(data_obj, 0, sizeof(struct WritePostDataData));
  599.  
  600.         data_obj->last_line_was_complete = TRUE;
  601.         data_obj->buffer = (char *) XP_ALLOC(POST_DATA_BUFFER_SIZE);
  602.  
  603.         if(!data_obj->buffer)
  604.         {
  605.             NET_free_write_post_data_object(data_obj);
  606.             *write_post_data_data=NULL;
  607.             return 0;
  608.         }
  609.  
  610.         if(URL_s->post_headers)
  611.             data_obj->headerSize = XP_STRLEN(URL_s->post_headers);
  612.         else
  613.             data_obj->headerSize = 0;
  614.  
  615.         data_obj->headerAmountSent = 0;
  616.         data_obj->CRSent = FALSE;
  617.         data_obj->LFSent = FALSE;
  618.         data_obj->amt_sent = 0;
  619.       }
  620.  
  621.     if(!data_obj->fp && URL_s->post_data_is_file)
  622.       {
  623.           XP_StatStruct stat_entry;
  624.  
  625.         /* Send the headers */
  626.         if( URL_s->post_headers && 
  627.             (data_obj->headerSize > data_obj->headerAmountSent) )
  628.         {
  629.             int32 amtWritten = 0;
  630.             amtWritten = PR_Write(sock, 
  631.                     URL_s->post_headers + data_obj->headerAmountSent, 
  632.                     data_obj->headerSize - data_obj->headerAmountSent);
  633.             
  634.             /* if there was a problem */
  635.             if( amtWritten < 0 ) {
  636.                 /* determine whether it was expected */
  637.                 if( net_expected_error(URL_s, (struct WritePostDataData **) write_post_data_data) )
  638.                     return 1;
  639.                 else 
  640.                     return(MK_TCP_WRITE_ERROR);
  641.             }
  642.  
  643. #ifdef DEBUG
  644.             NET_NTrace("Tx: ", 4);
  645.             NET_NTrace(URL_s->post_headers + data_obj->headerAmountSent, 
  646.                               amtWritten);
  647. #endif
  648.  
  649.             data_obj->headerAmountSent += amtWritten;
  650.  
  651.             if(data_obj->headerSize > data_obj->headerAmountSent)
  652.                 return 1;
  653.  
  654.         } /* END: URL_s->post_headers ... */
  655.  
  656.         /* stat the file to get the size
  657.          */
  658.         if(-1 != XP_Stat(URL_s->post_data, &stat_entry, xpFileToPost))
  659.           {
  660.               data_obj->file_size = stat_entry.st_size;
  661.           }
  662.               
  663.         /* open the post data file
  664.          */
  665.         data_obj->fp = XP_FileOpen(URL_s->post_data, xpFileToPost, XP_FILE_READ_BIN);
  666.  
  667.         if(!data_obj->fp)
  668.           {
  669.             URL_s->error_msg = NET_ExplainErrorDetails(
  670.                                                     MK_UNABLE_TO_LOCATE_FILE,
  671.                                                     URL_s->post_data);
  672.             NET_free_write_post_data_object(data_obj);
  673.             *write_post_data_data = NULL;
  674.             return(MK_UNABLE_TO_LOCATE_FILE);
  675.           }
  676.       }
  677.  
  678.     if(URL_s->post_data_is_file)
  679.       {
  680.         int32 amt_to_wrt;
  681.         int32 amt_wrt;
  682.  
  683.         int type = NET_URL_Type (URL_s->address);
  684.         XP_Bool quote_lines_p = (type == MAILTO_TYPE_URL ||
  685.                                  type == NEWS_TYPE_URL ||
  686.                                  type == INTERNAL_NEWS_TYPE_URL);
  687.  
  688.         /* do file based operations
  689.          */
  690.         if(data_obj->amt_in_buffer < 1 || data_obj->amt_sent >= data_obj->amt_in_buffer)
  691.           {
  692.             /* read more data from the file
  693.              */
  694.             if (quote_lines_p || add_crlf_to_line_endings)
  695.               {
  696.                 char *line;
  697.                 char *b = data_obj->buffer;
  698.                 int32 bsize = POST_DATA_BUFFER_SIZE;
  699.                 data_obj->amt_in_buffer =  0;
  700.                 do {
  701.                   int L;
  702.  
  703.                   line = XP_FileReadLine(b, bsize-5, data_obj->fp);
  704.  
  705.                   if (!line)
  706.                     break;
  707.  
  708.                   L = XP_STRLEN(line);
  709.  
  710.                   /* escape periods only if quote_lines_p is set
  711.                    */
  712.                   if (quote_lines_p &&
  713.                       data_obj->last_line_was_complete && line[0] == '.')
  714.                     {
  715.                       /* This line begins with "." so we need to quote it
  716.                          by adding another "." to the beginning of the line.
  717.                        */
  718.                       int i;
  719.                       line[L+1] = 0;
  720.                       for (i = L; i > 0; i--)
  721.                         line[i] = line[i-1];
  722.                       L++;
  723.                     }
  724.  
  725.                   /* set default */
  726.                   data_obj->last_line_was_complete = TRUE;
  727.  
  728.                   if (L > 1 && line[L-2] == CR && line[L-1] == LF)
  729.                      {
  730.                         /* already ok */
  731.                     }
  732.                   else if(L > 0 && (line[L-1] == LF || line[L-1] == CR))
  733.                     {
  734.                       /* only add the crlf if required
  735.                        * we still need to do all the
  736.                        * if comparisons here to know
  737.                        * if the line was complete
  738.                        */
  739.                       if(add_crlf_to_line_endings)
  740.                          {
  741.                             /* Change newline to CRLF. */
  742.                             L--;
  743.                             line[L++] = CR;
  744.                             line[L++] = LF;
  745.                             line[L] = 0;
  746.                         }
  747.                     }
  748.                   else
  749.                     {
  750.                       data_obj->last_line_was_complete = FALSE;
  751.                     }
  752.  
  753.                   bsize -= L;
  754.                   b += L;
  755.                   data_obj->amt_in_buffer += L;
  756.                 } while (line && bsize > 100);
  757.               }
  758.             else
  759.               {
  760.                 data_obj->amt_in_buffer = XP_FileRead(data_obj->buffer,
  761.                                                POST_DATA_BUFFER_SIZE-1,
  762.                                                data_obj->fp);
  763.               }
  764.  
  765. HG29784
  766.             
  767.             if(data_obj->amt_in_buffer < 1)
  768.               {
  769.                 /* end of file, all done
  770.                  */
  771.                 /* 
  772.                  * handled by NET_free_write_post_data_object 
  773.                  *
  774.                 XP_FileClose(data_obj->fp);
  775.                 */
  776.                 XP_ASSERT(data_obj->total_amt_sent >= data_obj->file_size);
  777.                 NET_free_write_post_data_object(data_obj);
  778.                 *write_post_data_data = NULL;
  779.                 return(0);
  780.               }
  781.  
  782.             data_obj->amt_sent = 0;
  783.           }
  784.  
  785.         amt_to_wrt = data_obj->amt_in_buffer-data_obj->amt_sent;
  786.  
  787.         /* write some data to the socket
  788.          */
  789.         amt_wrt = PR_Write(sock,
  790.                            data_obj->buffer+data_obj->amt_sent,
  791.                            amt_to_wrt);
  792.  
  793. #ifdef DEBUG
  794.         NET_NTrace("Tx: ", 4);
  795.         NET_NTrace(data_obj->buffer+data_obj->amt_sent,
  796.                    amt_to_wrt);
  797. #endif /* DEBUG */
  798.  
  799.         if(amt_wrt < 0) 
  800.           {
  801.             int err = PR_GetError();
  802.             if(err == PR_WOULD_BLOCK_ERROR 
  803.                 || err == PR_IS_CONNECTED_ERROR)
  804.                 return(1); /* continue */
  805.  
  806.             URL_s->error_msg = NET_ExplainErrorDetails(MK_TCP_WRITE_ERROR, err);
  807.             /*
  808.              * handled by net_free_write_post_data
  809.             XP_FileClose(data_obj->fp);
  810.             */
  811.  
  812.             NET_free_write_post_data_object(data_obj);
  813.             *write_post_data_data = NULL;
  814.  
  815.             return(MK_TCP_WRITE_ERROR);
  816.           }
  817.  
  818. #if defined(XP_UNIX) && defined(DEBUG)
  819.         if(amt_wrt < amt_to_wrt)
  820.            fprintf(stderr, "Fwrite wrote less than requested!\n");
  821. #endif
  822.  
  823.         /* safty for broken SSL_write */
  824.         if(amt_wrt > amt_to_wrt)
  825.             amt_wrt = amt_to_wrt;
  826.  
  827. #if defined(XP_UNIX) && defined(DEBUG)
  828.     if(MKLib_trace_flag)
  829.       {
  830.         fwrite("Tx: ", 1, 4, stderr);
  831.         fwrite(data_obj->buffer+data_obj->amt_sent, 1, amt_wrt, stderr);
  832.         fwrite("\n", 1, 1, stderr);
  833.       }
  834. #endif
  835.  
  836.         data_obj->amt_sent += amt_wrt;
  837.         data_obj->total_amt_sent += amt_wrt;
  838.  
  839.         /* return the amount of data written
  840.          * so that callers can provide progress
  841.          * if necessary.  If the amt_wrt was
  842.          * zero (I don't think it can ever happen)
  843.          * return 1 because zero means all done
  844.          */
  845.         if(amt_wrt > 0)
  846.             return(amt_wrt);
  847.         else
  848.             return(1);
  849.       }
  850.     else
  851.       {
  852.         /* do memory based operations */
  853.         int32 amtWritten;
  854.  
  855.         /* send the headers if there are any && and they haven't been sent */
  856.         if( URL_s->post_headers && (data_obj->headerSize > data_obj->headerAmountSent) )
  857.           {
  858.             amtWritten = PR_Write(sock, 
  859.                     URL_s->post_headers + data_obj->headerAmountSent, 
  860.                     data_obj->headerSize - data_obj->headerAmountSent);
  861.  
  862.             /* if there was a problem */
  863.             if(amtWritten < 0) {
  864.                 /* determine whether it was expected */
  865.                 if( net_expected_error(URL_s, (struct WritePostDataData **) write_post_data_data) )
  866.                     return 1;
  867.                 else 
  868.                     return(MK_TCP_WRITE_ERROR);
  869.             }
  870.  
  871. #ifdef DEBUG
  872.             NET_NTrace("Tx: ", 4);
  873.             NET_NTrace(URL_s->post_headers + data_obj->headerAmountSent, 
  874.                               amtWritten);
  875.             NET_NTrace("\n", 1);
  876. #endif
  877.  
  878.             data_obj->headerAmountSent += amtWritten;
  879.  
  880.             /* If all the header data hasn't been sent, return 1 (not done). */
  881.             if(data_obj->headerSize > data_obj->headerAmountSent)
  882.                 return 1;
  883.           }
  884.  
  885.         /* Separate the headers from the data with a CR and LF. */
  886.         if(!data_obj->CRSent) {
  887.             data_obj->buffer[0] = CR;
  888.             data_obj->buffer[1] = LF;
  889.             data_obj->buffer[2] = '\0';
  890.             amtWritten = PR_Write(sock, data_obj->buffer, XP_STRLEN(data_obj->buffer));
  891.  
  892.             if(amtWritten < 0) {
  893.                 /* determine whether it was expected */
  894.                 if( net_expected_error(URL_s, (struct WritePostDataData **) write_post_data_data) )
  895.                     return 1;
  896.                 else 
  897.                     return(MK_TCP_WRITE_ERROR);
  898.               }
  899.             /* If no data was sent, return 1 (not done). */
  900.             if(amtWritten == 0)
  901.                 return 1;
  902.  
  903.             if(amtWritten >= 1)
  904.                 data_obj->CRSent = TRUE;
  905.             if(amtWritten >= 2)
  906.                 data_obj->LFSent = TRUE;
  907.         }
  908.  
  909.         if(!data_obj->LFSent) {
  910.             data_obj->buffer[0] = LF;
  911.             data_obj->buffer[1] = '\0';
  912.             amtWritten = PR_Write(sock, data_obj->buffer, XP_STRLEN(data_obj->buffer));
  913.  
  914.             if(amtWritten < 0) {
  915.                 /* determine whether it was expected */
  916.                 if( net_expected_error(URL_s, (struct WritePostDataData **) write_post_data_data) )
  917.                     return 1;
  918.                 else 
  919.                     return(MK_TCP_WRITE_ERROR);
  920.               }
  921.             /* If no data was sent, return 1 (not done). */
  922.             if(amtWritten == 0)
  923.                 return 1;
  924.             data_obj->LFSent = TRUE;
  925.  
  926.             TRACEMSG(("Adding \\n to command"));
  927.         }
  928.  
  929.         if(!URL_s->post_data)
  930.           {
  931.             NET_free_write_post_data_object(data_obj);
  932.             *write_post_data_data = NULL;
  933.             return(MK_OUT_OF_MEMORY);
  934.           }
  935.  
  936.         /* Send the data if we haven't already sent it */
  937.         if(URL_s->post_data_size > data_obj->amt_sent) {
  938.             amtWritten = PR_Write(sock,
  939.                                 URL_s->post_data+data_obj->amt_sent,
  940.                                 URL_s->post_data_size-data_obj->amt_sent);
  941.  
  942.             if(amtWritten < 0) {
  943.                 /* determine whether it was expected */
  944.                 if( net_expected_error(URL_s, (struct WritePostDataData **) write_post_data_data) )
  945.                     return 1;
  946.                 else 
  947.                     return(MK_TCP_WRITE_ERROR);
  948.               }
  949.             /* If no data was sent, return 1 (not done). */    
  950.             if(amtWritten == 0)
  951.                 return 1;
  952.  
  953. #ifdef DEBUG
  954.             NET_NTrace("Tx: ", 4);
  955.             NET_NTrace(URL_s->post_data+data_obj->amt_sent,
  956.                           amtWritten);
  957.             NET_NTrace("\n", 1);
  958. #endif
  959.  
  960.             data_obj->amt_sent += amtWritten;
  961.  
  962.             /* if all data has been written, return done */
  963.             if(data_obj->amt_sent >= URL_s->post_data_size)    {
  964.                 NET_free_write_post_data_object(data_obj);
  965.                 *write_post_data_data = NULL;
  966.                 return 0;
  967.             }
  968.             else {
  969.                 return amtWritten;
  970.             }
  971.         }
  972.         else {
  973.             NET_free_write_post_data_object(data_obj);
  974.             *write_post_data_data = NULL;
  975.             return 0;
  976.         }
  977.       }
  978.  
  979.     /* By this time all headers and data should have been sent, shouldn't get here */
  980.     XP_ASSERT(0);
  981.     NET_free_write_post_data_object(data_obj);
  982.     *write_post_data_data = NULL;
  983.     return(-1); /* shouldn't ever get here */
  984.  
  985. }
  986.  
  987. void
  988. NET_ParseContentTypeHeader(MWContext *context, char *value, URL_Struct *URL_s, XP_Bool is_http)
  989. {
  990.     char *first_arg, *next_arg;
  991.  
  992.     if(URL_s->preset_content_type)
  993.         return;
  994.  
  995.     first_arg = XP_STRTOK(value, ";");
  996.  
  997.     StrAllocCopy(URL_s->content_type, XP_StripLine(value));
  998.     TRACEMSG(("Found content_type: %s",URL_s->content_type));
  999.    
  1000.     /* assign and compare
  1001.      *
  1002.      * search for charset
  1003.      * and boundry
  1004.      */
  1005.     while((next_arg = XP_STRTOK(NULL, ";")) != NULL)
  1006.       {
  1007.         next_arg = XP_StripLine(next_arg);
  1008.  
  1009.         if(!strncasecomp(next_arg,"CHARSET=", 8))
  1010.           {
  1011. #ifdef MOZILLA_CLIENT
  1012.             char *charset_tag = NET_RemoveQuotes(next_arg+8);
  1013.             /* 
  1014.              * To make http LOAD-FROM-NET and LOAD-FROM-CACHE
  1015.              * charset tag handling consistant just put the http 
  1016.              * charset info in the url struct.
  1017.              * We will use this later when setting up charset converter.
  1018.              * (we do this because: on a reload from cache this code will not get called)
  1019.              */
  1020.             if (is_http)
  1021.             {
  1022.                 /* record HTTP charset tag so we can: */
  1023.                 /*   1) use it to figure out the doc_csid */
  1024.                 /*   2) report it to the user */
  1025.                 StrAllocCopy(URL_s->charset, charset_tag);
  1026.                 TRACEMSG(("Found HTTP charset: %s", charset_tag));
  1027.             }
  1028.             else
  1029.             {
  1030.                 INTL_CCCReportMetaCharsetTag(context, charset_tag);
  1031.                 TRACEMSG(("Found Meta charset: %s", charset_tag));
  1032.             }
  1033. #else
  1034.             XP_ASSERT(0);
  1035. #endif /* MOZILLA_CLIENT */
  1036.           }
  1037.         else if(!strncasecomp(next_arg,"BOUNDARY=", 9))
  1038.           {
  1039.             StrAllocCopy(URL_s->boundary, NET_RemoveQuotes(next_arg+9));
  1040.             TRACEMSG(("Found boundary: %s", URL_s->boundary));
  1041.           }
  1042.         else if(!strncasecomp(next_arg,"AUTOSCROLL", 10))
  1043.           {
  1044.  
  1045. #define DEFAULT_AUTO_SCROLL_BUFFER 100
  1046.             if(*next_arg+10 == '=')
  1047.                 URL_s->auto_scroll = atoi(NET_RemoveQuotes(next_arg+11));
  1048.  
  1049.             if(!URL_s->auto_scroll)
  1050.                    URL_s->auto_scroll = DEFAULT_AUTO_SCROLL_BUFFER;
  1051.  
  1052.             TRACEMSG(("Found autoscroll attr.: %ud", URL_s->auto_scroll));
  1053.           }
  1054.       }
  1055. }
  1056.  
  1057. /* parse a mime header.
  1058.  * 
  1059.  * Both name and value strings will be modified during
  1060.  * parsing.  If you need to retain your strings make a
  1061.  * copy before passing them in.
  1062.  *
  1063.  * Values will be placed in the URL struct.
  1064.  *
  1065.  * returns TRUE if it found a valid header
  1066.  * and FALSE if it didn't
  1067.  */
  1068.  
  1069. PUBLIC Bool
  1070. NET_ParseMimeHeader(FO_Present_Types outputFormat,
  1071.                     MWContext  *context, 
  1072.                     URL_Struct *URL_s, 
  1073.                     char       *name, 
  1074.                     char       *value,
  1075.                     XP_Bool       is_http)
  1076. {
  1077.     Bool  found_one = FALSE;
  1078.     Bool  ret_value = FALSE;
  1079.     char  empty_string[2];
  1080.     char  *colon_ptr;
  1081.  
  1082.     if(!name || !URL_s)
  1083.         return(FALSE);
  1084.  
  1085.     name = XP_StripLine(name);    
  1086.  
  1087.     if(value)
  1088.       {
  1089.         value = XP_StripLine(value);    
  1090.       }
  1091.     else
  1092.       {
  1093.         *empty_string = '\0';
  1094.         value = empty_string;
  1095.       }
  1096.  
  1097.     colon_ptr = XP_STRCHR(name, ':');
  1098.     if (colon_ptr) {
  1099.         *colon_ptr = '\0';
  1100.         }
  1101.     ret_value = NET_AddToAllHeaders(URL_s, name, value);
  1102.     if (colon_ptr) {
  1103.         *colon_ptr = ':';
  1104.         }
  1105.     if (!ret_value) {
  1106.         return(FALSE);
  1107.         }
  1108.  
  1109.     switch(toupper(*name))
  1110.       {
  1111.         case 'A':
  1112.             if(!strncasecomp(name,"ACCEPT-RANGES:",14)
  1113.                 || !strncasecomp(name, "ALLOW-RANGES:",13))
  1114.               {
  1115.                 char * next_arg = XP_STRTOK(value, ";");
  1116.  
  1117.                 found_one = TRUE;
  1118.  
  1119.                 while(next_arg)
  1120.                   {
  1121.                     next_arg = XP_StripLine(next_arg);
  1122.  
  1123.                     if(!strncasecomp(next_arg,"BYTES", 5))
  1124.                       {
  1125.                         TRACEMSG(("Document Allows for BYTERANGES!"));
  1126.                         URL_s->server_can_do_byteranges = TRUE;
  1127.                       }
  1128.  
  1129.                     next_arg = XP_STRTOK(NULL, ";");
  1130.                   }
  1131.               }
  1132.             else if(!strncasecomp(name, "AGE:",4)) 
  1133.             {
  1134.                 long age;
  1135.  
  1136.                 XP_STRTOK(value, ";"); /* terminate at ';' */
  1137.  
  1138.                 age = atol(value);
  1139.                 /* Small deviation from the spec. Assumption being made-
  1140.                    Req. time ~= Resp Time ~= now */
  1141.                 if (URL_s->server_date)
  1142.                 {
  1143.                     time_t now = time(NULL);
  1144.                     time_t correction = now - MAX(age, MAX(0, now- URL_s->server_date));
  1145.                     if (URL_s->expires)
  1146.                         URL_s->expires += correction;
  1147.                 }
  1148.             }
  1149.         case 'C':
  1150.             if (!strncasecomp(name,"CACHE-CONTROL:",14))
  1151.             {
  1152.             /* Potential values include */
  1153.                 /* public */
  1154.                 /* private[=field-name] */
  1155.                 /* no-cache [=field-name] */
  1156.                 /* no-store */
  1157.                 /* no-transform - this is only applicable for proxies and hence not put here*/
  1158.                 /* must-revalidate */
  1159.                 /* proxy-revalidate */
  1160.                 /* max-age=delta-seconds */
  1161.                 /* s-maxage=delta-seconds */
  1162.  
  1163.                 /* any cache extension */
  1164.  
  1165.                 char * control = NET_RemoveQuotes(value);
  1166.  
  1167.                 if (!strncasecomp(control, "NO-CACHE", 8))
  1168.                 {
  1169.                     /* same as pragma=no-cache */
  1170.                     URL_s->dont_cache = TRUE;
  1171.                 }
  1172.                 else if (!strncasecomp(control, "MAX-AGE=", 8))
  1173.                 {
  1174.                     /* Takes precedence over the Expires header. 
  1175.                        Corrected Expires is Max-age + Server Date */
  1176.                     if (URL_s->server_date)
  1177.                     {
  1178.                         URL_s->expires = URL_s->server_date + atol(XP_STRTOK(control+8,";")); 
  1179.                     }
  1180.                 }
  1181. #if 0    /* Unimplemented */
  1182.                 else if (!strncasecomp(control, "PUBLIC", 6))
  1183.                 {
  1184.                     /* Place holder for shared cache concepts */
  1185.                 }
  1186.                 else if (!strncasecomp(control, "PRIVATE", 7)) 
  1187.                 {
  1188.                     /* Place holder for shared cache concepts */
  1189.                 }
  1190.                 else if (!strncasecomp(control, "NO-STORE", 8))
  1191.                 {
  1192.                     /* According to the spec this "should" disable explicit saving 
  1193.                        of the document outside the caching system, eg. in "Save As..."
  1194.                        dialogs. Since this idea sucks, this is a place holder. */
  1195.                 }
  1196.                 else if (!strncasecomp(control, "MUST-REVALIDATE", 15))
  1197.                 {
  1198.                     /* The cache must do an end-to-end revalidation every time, if
  1199.                        the response headers suggest an entity is stale. We do this
  1200.                        anyway. */
  1201.                 }
  1202.                 else if (!strncasecomp(control, "PROXY-REVALIDATE", 16))
  1203.                 {
  1204.                     /* Same as must-revalidate except that it does not apply to 
  1205.                        non-shared user agents (like us) */
  1206.                 }
  1207.                 else if (!strncasecomp(control, "S-MAXAGE", 8))
  1208.                 {
  1209.                     /* Applicable for shared caches. Place holder. */
  1210.                 }
  1211.                 else 
  1212.                 {
  1213.                     /* A new cache extension */
  1214.                 }
  1215. #endif /* Unimplemented */
  1216.             }
  1217.             else if(!strncasecomp(name,"CONTENT-DISPOSITION:",20))
  1218.               {
  1219.                 char *next_arg;
  1220.  
  1221.                 found_one = TRUE;
  1222.  
  1223.                 next_arg = XP_STRTOK(value, ";");
  1224.  
  1225.                 while(next_arg)
  1226.                   {  
  1227.                     next_arg = XP_StripLine(next_arg);
  1228.                 
  1229.                     if(!strncasecomp(next_arg,"filename=", 9))
  1230.                       {
  1231.                         StrAllocCopy(URL_s->content_name,
  1232.                                      NET_RemoveQuotes(next_arg+9));
  1233.                       }
  1234.                     next_arg = XP_STRTOK(NULL, ";");
  1235.                   }
  1236.     
  1237.               }
  1238.             else if(!strncasecomp(name,"CONTENT-TYPE:",13))
  1239.               {
  1240.                 found_one = TRUE;
  1241.                 NET_ParseContentTypeHeader(context, value, URL_s, is_http);
  1242.               }
  1243.             else if(!strncasecomp(name,"CONTENT-LENGTH:",15))
  1244.               {
  1245.                 found_one = TRUE;
  1246.  
  1247.                 XP_STRTOK(value, ";"); /* terminate at ';' */
  1248.                 
  1249.                 /* don't reset the content-length if
  1250.                  * we have already set it from the content-range
  1251.                  * header.  If high_range is set then we must
  1252.                  * have seen a content-range header.
  1253.                  */
  1254.                 if(!URL_s->high_range)
  1255.                     URL_s->content_length = atol(value);
  1256.               }
  1257.             else if(!strncasecomp(name,"CONTENT-ENCODING:",17))
  1258.               {
  1259.                 found_one = TRUE;
  1260.  
  1261.                 XP_STRTOK(value, ";"); /* terminate at ';' */
  1262.                 StrAllocCopy(URL_s->content_encoding, value);
  1263.               }
  1264.             else if(!strncasecomp(name,"CONTENT-RANGE:",14))
  1265.               {
  1266.                 unsigned long low, high, length;
  1267.                 XP_STRTOK(value, ";"); /* terminate at ';' */
  1268.  
  1269.                 /* range header looks like:
  1270.                  * Range: bytes x-y/z
  1271.                  * where:
  1272.                  *
  1273.                  * X     is the number of the first byte returned
  1274.                  *       (the first byte is byte number zero).
  1275.                  *
  1276.                  * Y     is the number of the last byte returned
  1277.                  *       (in case of the end of the document this
  1278.                  *       is one smaller than the size of the document
  1279.                  *       in bytes).
  1280.                  *
  1281.                  * Z     is the total size of the document in bytes.
  1282.                  *
  1283.                  * Scan through temp variables because %l is 64 bits on OSF1
  1284.                  */
  1285.                 sscanf(value, "bytes %lu-%lu/%lu", &low, &high, &length);
  1286.                 URL_s->low_range = (int32) low;
  1287.                 URL_s->high_range = (int32) high;
  1288.                 URL_s->content_length = (int32) length;
  1289.  
  1290.                 /* if we get a range header set the "can-do-byteranges"
  1291.                  * since it must be doing byteranges
  1292.                  */
  1293.                 URL_s->server_can_do_byteranges = TRUE;
  1294.               }
  1295.             else if(!strncasecomp(name,"CONNECTION:",11))
  1296.               {
  1297.                 XP_STRTOK(value, ";"); /* terminate at ';' */
  1298.                 XP_STRTOK(value, ","); /* terminate at ',' */
  1299.                 if(!strcasecomp("KEEP-ALIVE", XP_StripLine(value)))
  1300.                     URL_s->can_reuse_connection = TRUE;
  1301.                 if(!strcasecomp("CLOSE", XP_StripLine(value)))
  1302.                     URL_s->can_reuse_connection = FALSE;
  1303.               }
  1304.             break;
  1305.  
  1306.         case 'D':
  1307.             if(!strncasecomp(name,"DATE:",5))
  1308.               {
  1309.                 found_one = TRUE;
  1310.                 URL_s->server_date = NET_ParseDate(value);
  1311.               }
  1312. #if 0
  1313.             else if(!strncasecomp(name,"DEST-IP:",8))
  1314.               {
  1315.                 found_one = TRUE;
  1316.                 URL_s->destIP = XP_STRDUP(value);
  1317.               }
  1318. #endif
  1319.             break;
  1320.         case 'E':
  1321.             if(!strncasecomp(name,"EXPIRES:",8))
  1322.               {
  1323.                 char *cp, *expires = NET_RemoveQuotes(value);
  1324.                 Bool is_number=TRUE;
  1325.                 
  1326.                 /* Expires: 123   - number of seconds
  1327.                  * Expires: date  - absolute date
  1328.                  */
  1329.  
  1330.                 XP_STRTOK(value, ";"); /* terminate at ';' */
  1331.  
  1332.                 /* check to see if the expires date is just a
  1333.                  * value in seconds
  1334.                  */
  1335.                 for(cp = expires; *cp != '\0'; cp++)
  1336.                     if(!isdigit(*cp))
  1337.                       {
  1338.                         is_number=FALSE;
  1339.                         break;
  1340.                       }
  1341.                 
  1342.                 if(is_number)
  1343.                     URL_s->expires = time(NULL) + atol(expires);
  1344.                 else
  1345.                     URL_s->expires = NET_ParseDate(expires);
  1346.  
  1347.                 /* if we couldn't parse the date correctly
  1348.                  * make it already expired, as per the HTTP spec
  1349.                  */
  1350.                 if(!URL_s->expires)
  1351.                     URL_s->expires = 1;
  1352.  
  1353.                 found_one = TRUE;
  1354.               }
  1355.             else if(!strncasecomp(name,"EXT-CACHE:",10))
  1356.               {
  1357. #ifdef MOZILLA_CLIENT
  1358.                 char * next_arg = XP_STRTOK(value, ";");
  1359.                 char * name=0;
  1360.                 char * instructions=0;
  1361.  
  1362.                 found_one = TRUE;
  1363.  
  1364.                 while(next_arg)
  1365.                   {
  1366.                     next_arg = XP_StripLine(next_arg);
  1367.  
  1368.                     if(!strncasecomp(next_arg,"name=", 5))
  1369.                       {
  1370.                         TRACEMSG(("Found external cache name: %s", next_arg+5));
  1371.                         name = NET_RemoveQuotes(next_arg+5);
  1372.                       }
  1373.                     else if(!strncasecomp(next_arg,"instructions=", 13))
  1374.                       {
  1375.                         TRACEMSG(("Found external cache instructions: %s", 
  1376.                                   next_arg+13));
  1377.                         instructions = NET_RemoveQuotes(next_arg+13);
  1378.                       }
  1379.  
  1380.                     next_arg = XP_STRTOK(NULL, ";");
  1381.                   }
  1382.     
  1383.                 if(name)
  1384.                     NET_OpenExtCacheFAT(context, name, instructions);
  1385. #else
  1386.                 XP_ASSERT(0);
  1387. #endif /* MOZILLA_CLIENT */
  1388.               }
  1389.             else if (!strncasecomp(name, "ETAG:",5))
  1390.             {
  1391.                 /* Weak Validators are skipped for now*/
  1392.                 char* etag;
  1393.                 if (!strncasecomp(value, "W/", 2))
  1394.                     etag = NET_RemoveQuotes(value+2);
  1395.                 else
  1396.                     etag = NET_RemoveQuotes(value);
  1397.  
  1398.                 StrAllocCopy(URL_s->etag,etag);
  1399.             }
  1400.             break;
  1401.  
  1402.         case 'L':
  1403.             if(!strncasecomp(name,"LOCATION:",9))
  1404.               {
  1405.                 found_one = TRUE;
  1406.  
  1407.                 /* don't do this here because a url can
  1408.                  * contain a ';'
  1409.                  * XP_STRTOK(value, ";"); 
  1410.                  */
  1411.  
  1412.                 URL_s->redirecting_url = NET_MakeAbsoluteURL(
  1413.                                                     URL_s->address,
  1414.                                                     XP_StripLine(value));
  1415.  
  1416.                 TRACEMSG(("Found location: %s\n",URL_s->redirecting_url));
  1417.  
  1418.                 if(MOCHA_TYPE_URL == NET_URL_Type(URL_s->redirecting_url))
  1419.                   {
  1420.                     /* don't allow mocha URL's as refresh
  1421.                      */
  1422.                     FREE_AND_CLEAR(URL_s->redirecting_url);
  1423.                   }
  1424.               }
  1425.             else if(!strncasecomp(name,"LAST-MODIFIED:",14))
  1426.               {
  1427.                 found_one = TRUE;
  1428.  
  1429.                 URL_s->last_modified = NET_ParseDate(value);
  1430.                 TRACEMSG(("Found last modified date: %d\n",URL_s->last_modified));
  1431.               }
  1432.             else if(!strncasecomp(name,"LINK:",5))
  1433.               {
  1434. #define PAGE_SERVICES_REL "pageServices"
  1435.                 char * next_arg = XP_STRTOK(value, ";");
  1436.                 char * link_val;
  1437.                 enum { UNKNOWN_REL_TYPE, PAGE_SERVICES_REL_TYPE } rel_type;
  1438.  
  1439.                 found_one = TRUE;
  1440.  
  1441.                 rel_type = UNKNOWN_REL_TYPE;
  1442.  
  1443.                 /* strip the < and > from the url */
  1444.                 if(*value == '<')
  1445.                 {
  1446.                    value++;
  1447.                    /* strip the end one too */
  1448.                    value[XP_STRLEN(value)-1] = '\0';
  1449.                 }
  1450.  
  1451.                 /* ok if malloc fails */
  1452.                 link_val = NET_MakeAbsoluteURL(URL_s->address,
  1453.                                                XP_StripLine(value));
  1454.                 while(next_arg)
  1455.                   {
  1456.                     next_arg = XP_StripLine(next_arg);
  1457.  
  1458.                     if(!strncasecomp(next_arg,"rel=", 4))
  1459.                       {
  1460.                         char * rel = NET_RemoveQuotes(next_arg+4);
  1461.  
  1462.                         if(!strcasecomp(rel, PAGE_SERVICES_REL))
  1463.                             rel_type = PAGE_SERVICES_REL_TYPE;
  1464.                       }
  1465.  
  1466.                     next_arg = XP_STRTOK(NULL, ";");
  1467.                   }
  1468.  
  1469.                 /* if we fount a rel for page services assign it */
  1470.                 if(rel_type == PAGE_SERVICES_REL_TYPE)
  1471.                     URL_s->page_services_url = link_val;
  1472.                 else
  1473.                     XP_FREEIF(link_val);
  1474.     
  1475.               }
  1476.             break;
  1477.  
  1478.         case 'P':
  1479.             if(!strncasecomp(name,"PROXY-AUTHENTICATE:",19))
  1480.               {
  1481.                 char *auth = value;
  1482.  
  1483.                 found_one = TRUE;
  1484.  
  1485.                 XP_STRTOK(value, ";"); /* terminate at ';' */
  1486.  
  1487.                 if (net_IsBetterAuth(auth, URL_s->proxy_authenticate))
  1488.                   StrAllocCopy(URL_s->proxy_authenticate, auth);
  1489.               }
  1490.             else if(!strncasecomp(name,"PROXY-CONNECTION:",17))
  1491.               {
  1492.                 XP_STRTOK(value, ";"); /* terminate at ';' */
  1493.                 XP_STRTOK(value, ","); /* terminate at ',' */
  1494.                 if(!strcasecomp("KEEP-ALIVE", XP_StripLine(value)))
  1495.                     URL_s->can_reuse_connection = TRUE;
  1496.               }
  1497.             else if(!strncasecomp(name,"PRAGMA:",7))
  1498.               {
  1499.                 found_one = TRUE;
  1500.  
  1501.                 XP_STRTOK(value, ";"); /* terminate at ';' */
  1502.  
  1503.                 if(!strcasecomp(value, "NO-CACHE"))
  1504.                     URL_s->dont_cache = TRUE;
  1505.               }
  1506.             break;
  1507.  
  1508.         case 'R':
  1509.             
  1510.             if(!strncasecomp(name,"RANGE:",6))
  1511.               {
  1512.                 unsigned long low, high, length;
  1513.                 XP_STRTOK(value, ";"); /* terminate at ';' */
  1514.  
  1515.                 /* range header looks like:
  1516.                  * Range: bytes x-y/z
  1517.                   * where:
  1518.                  *
  1519.                    * X     is the number of the first byte returned 
  1520.                  *       (the first byte is byte number zero).
  1521.                  *
  1522.                    * Y     is the number of the last byte returned 
  1523.                  *         (in case of the end of the document this 
  1524.                  *       is one smaller than the size of the document
  1525.                    *       in bytes).
  1526.                  *
  1527.                    * Z     is the total size of the document in bytes.
  1528.                  *
  1529.                  * Scan through temp variables because %l is 64 bits on OSF1
  1530.                  */
  1531.                 sscanf(value, "bytes %lu-%lu/%lu", &low, &high, &length); 
  1532.                 URL_s->low_range = (int32) low;
  1533.                 URL_s->high_range = (int32) high;
  1534.                 URL_s->content_length = (int32) length;
  1535.  
  1536.                 /* if we get a range header set the "can-do-byteranges"
  1537.                  * since it must be doing byteranges
  1538.                  */
  1539.                 URL_s->server_can_do_byteranges = TRUE;
  1540.               }
  1541.             else if(!strncasecomp(name,"REFRESH:",8) && !EDT_IS_EDITOR(context))
  1542.               {
  1543.                 char *first_arg, *next_arg;
  1544.  
  1545.                 found_one = TRUE;
  1546.  
  1547.                 /* clear any previous refresh URL */
  1548.                 if(URL_s->refresh_url)
  1549.                   {
  1550.                     FREE(URL_s->refresh_url);
  1551.                     URL_s->refresh_url=0;
  1552.                   }
  1553.  
  1554.                 first_arg = XP_STRTOK(value, ";");
  1555.  
  1556.                 URL_s->refresh = atol(value);
  1557.                 TRACEMSG(("Found refresh header: %d",URL_s->refresh));
  1558.  
  1559.                 /* assign and compare
  1560.                  */
  1561.                 while((next_arg = XP_STRTOK(NULL, ";")) != NULL)
  1562.                   {
  1563.                     next_arg = XP_StripLine(next_arg);
  1564.  
  1565.  
  1566.                     if(!strncasecomp(next_arg,"URL=", 4))
  1567.                       {
  1568.                         URL_s->refresh_url = NET_MakeAbsoluteURL(
  1569.                                                 URL_s->address,
  1570.                                                 NET_RemoveQuotes(next_arg+4));
  1571.                         TRACEMSG(("Found refresh url: %s",
  1572.                                                 URL_s->refresh_url));
  1573.  
  1574.                         if(MOCHA_TYPE_URL == NET_URL_Type(URL_s->refresh_url))
  1575.                           {
  1576.                             /* don't allow mocha URL's as refresh
  1577.                              */
  1578.                             FREE_AND_CLEAR(URL_s->refresh_url);
  1579.                           }
  1580.                       }
  1581.                   }
  1582.  
  1583.                 if(!URL_s->refresh_url)
  1584.                     StrAllocCopy(URL_s->refresh_url, URL_s->address);
  1585.               }
  1586.             break;
  1587.  
  1588.         case 'S':
  1589.             if(!strncasecomp(name,"SET-COOKIE:",11))
  1590.               {
  1591.                 found_one = TRUE;
  1592.                 NET_SetCookieStringFromHttp(outputFormat, URL_s, context, URL_s->address, value);
  1593.               }
  1594.             else if(!strncasecomp(name, "SERVER:", 7))
  1595.               {
  1596.                 found_one = TRUE;
  1597.  
  1598.                 if(strcasestr(value, "NETSITE"))
  1599.                     URL_s->is_netsite = TRUE;
  1600.                 else if(strcasestr(value, "NETSCAPE"))
  1601.                     URL_s->is_netsite = TRUE;
  1602.               }
  1603.             break;
  1604.  
  1605.         case 'T':
  1606.             if(!strncasecomp(name,"TRANSFER-ENCODING:",18))
  1607.               {
  1608.                 found_one = TRUE;
  1609.  
  1610.                 XP_STRTOK(value, ";"); /* terminate at ';' */
  1611.                 StrAllocCopy(URL_s->transfer_encoding, value);
  1612.               }
  1613.  
  1614.         case 'W':
  1615.             if(!strncasecomp(name,"WWW-AUTHENTICATE:",17))
  1616.               {
  1617.                 found_one = TRUE;
  1618.  
  1619.                 XP_STRTOK(value, ";"); /* terminate at ';' */
  1620.  
  1621.                 StrAllocCopy(URL_s->authenticate, value);
  1622.               }
  1623.             else if(!strncasecomp(name, "WWW-PROTECTION-TEMPLATE:", 24))
  1624.               {
  1625.                 found_one = TRUE;
  1626.  
  1627.                 XP_STRTOK(value, ";"); /* terminate at ';' */
  1628.  
  1629.                 StrAllocCopy(URL_s->protection_template, value);
  1630.                }
  1631.             else if(!strncasecomp(name, "WINDOW-TARGET:", 14))
  1632.               {
  1633.                 found_one = TRUE;
  1634.  
  1635.                 XP_STRTOK(value, ";"); /* terminate at ';' */
  1636.  
  1637.                 if (URL_s->window_target == NULL)
  1638.           {
  1639.             if ((XP_IS_ALPHA(value[0]) != FALSE)||
  1640.                 (XP_IS_DIGIT(value[0]) != FALSE)||
  1641.                 (value[0] == '_'))
  1642.               {
  1643.                 StrAllocCopy(URL_s->window_target, value);
  1644.               }
  1645.           }
  1646.                }
  1647.             break;
  1648.  
  1649.         default:
  1650.         /* ignore other headers */
  1651.             break;
  1652.       }
  1653.  
  1654.     return(found_one);
  1655. }
  1656.  
  1657.  
  1658.  
  1659. /* scans a line for references to URL's and turns them into active
  1660.  * links.  If the output size is exceeded the line will be
  1661.  * truncated.  "output" must be at least "output_size" characters
  1662.  * long
  1663.  *
  1664.  * This also quotes other HTML forms, and italicizes citations,
  1665.  * unless `urls_only' is true.
  1666.  */
  1667.  
  1668. #ifndef MOZILLA_CLIENT
  1669.  /* If we're not in the client, stub out the libmsg interface to the 
  1670.     citation-highlighting code.
  1671.   */
  1672. # define MSG_PlainFont      0
  1673. # define MSG_BoldFont       1
  1674. # define MSG_ItalicFont     2
  1675. # define MSG_BoldItalicFont 3
  1676. # define MSG_NormalSize     4
  1677. # define MSG_Bigger         5
  1678. # define MSG_Smaller        6
  1679. #endif /* MOZILLA_CLIENT */
  1680.  
  1681. static MSG_FONT CitationFont = MSG_ItalicFont;
  1682. static int32 CitationSize = 0;
  1683. static char *CitationColor = 0;
  1684. static int CitationDataValid = -1; /* -1=first time, 0=changed; 1=data ok  */
  1685.  
  1686.  
  1687.  
  1688. /* fix Mac warning about missing prototype */
  1689. int PR_CALLBACK
  1690. net_citation_style_changed(const char* name, void* closure);
  1691.  
  1692. int PR_CALLBACK
  1693. net_citation_style_changed(const char* name, void* closure)
  1694. {
  1695.   CitationDataValid = 0;
  1696.   return 0;
  1697. }
  1698.  
  1699.  
  1700.  
  1701.  
  1702.  
  1703. PUBLIC int
  1704. NET_ScanForURLs(MSG_Pane* pane, const char *input, int32 input_size,
  1705.                 char *output, int output_size, XP_Bool urls_only)
  1706. {
  1707.   int col = 0;
  1708.   const char *cp;
  1709.   const char *end = input + input_size;
  1710.   char *output_ptr = output;
  1711.   char *end_of_buffer = output + output_size - 40; /* add safty zone :( */
  1712.   Bool line_is_citation = FALSE;
  1713.   const char *cite_open1, *cite_close1;
  1714.   const char *cite_open2, *cite_close2;
  1715.   const char* color = NULL;
  1716.  
  1717.   if (urls_only)
  1718.     {
  1719.       cite_open1 = cite_close1 = "";
  1720.       cite_open2 = cite_close2 = "";
  1721.     }
  1722.   else
  1723.     {
  1724. #ifdef MOZILLA_CLIENT
  1725.       if (CitationDataValid != 1) {
  1726.           int32 value = (int32) MSG_ItalicFont;
  1727.           if (CitationDataValid < 0) {
  1728.               PREF_RegisterCallback("mail.quoted_style",
  1729.                                     net_citation_style_changed,
  1730.                                     NULL);
  1731.               PREF_RegisterCallback("mail.quoted_size",
  1732.                                     net_citation_style_changed,
  1733.                                     NULL);
  1734.               PREF_RegisterCallback("mail.citation_color",
  1735.                                     net_citation_style_changed,
  1736.                                     NULL);
  1737.           }
  1738.           PREF_GetIntPref("mail.quoted_style", &value);
  1739.           CitationFont = (MSG_FONT) value;
  1740.           CitationSize = 0;
  1741.           PREF_GetIntPref("mail.quoted_size", &CitationSize);
  1742.           FREEIF(CitationColor);
  1743.           CitationColor = NULL;
  1744.           PREF_CopyCharPref("mail.citation_color", &CitationColor);
  1745.           CitationDataValid = 1;
  1746.       }
  1747.  
  1748.       switch (CitationFont)
  1749.         {
  1750.         case MSG_PlainFont:
  1751.           cite_open1 = "", cite_close1 = "";
  1752.           break;
  1753.         case MSG_BoldFont:
  1754.           cite_open1 = "<B>", cite_close1 = "</B>";
  1755.           break;
  1756.         case MSG_ItalicFont:
  1757.           cite_open1 = "<I>", cite_close1 = "</I>";
  1758.           break;
  1759.         case MSG_BoldItalicFont:
  1760.           cite_open1 = "<B><I>", cite_close1 = "</I></B>";
  1761.           break;
  1762.         default:
  1763.           XP_ASSERT(0);
  1764.           cite_open1 = cite_close1 = "";
  1765.           break;
  1766.         }
  1767.       switch (CitationSize) {
  1768.       case 0:                    /* Normal */
  1769.           cite_open2 = "", cite_close2 = "";
  1770.           break;
  1771.       case 1:                    /* Bigger */
  1772.           cite_open2 = "<FONT SIZE=+1>", cite_close2 = "</FONT>";
  1773.           break;
  1774.       case 2:                    /* Smaller */
  1775.       case -1:                /* backwards compatability with some old code */
  1776.           cite_open2 = "<FONT SIZE=-1>", cite_close2 = "</FONT>";
  1777.           break;
  1778.       default:
  1779.           XP_ASSERT(0);
  1780.           cite_open2 = cite_close2 = "";
  1781.           break;
  1782.       }
  1783.  
  1784. #else
  1785.         XP_ASSERT(0);
  1786. #endif /* MOZILLA_CLIENT */
  1787.     }
  1788.  
  1789.   if (!urls_only)
  1790.     {
  1791.       /* Decide whether this line is a quotation, and should be italicized.
  1792.          This implements the following case-sensitive regular expression:
  1793.  
  1794.             ^[ \t]*[A-Z]*[]>]
  1795.  
  1796.          Which matches these lines:
  1797.  
  1798.             > blah blah blah
  1799.                  > blah blah blah
  1800.             LOSER> blah blah blah
  1801.             LOSER] blah blah blah
  1802.        */
  1803.       const char *s = input;
  1804.       while (s < end && XP_IS_SPACE (*s)) s++;
  1805.       while (s < end && *s >= 'A' && *s <= 'Z') s++;
  1806.  
  1807.       if (s >= end)
  1808.         ;
  1809.       else if (input_size >= 6 && *s == '>' &&
  1810.                !XP_STRNCMP (input, ">From ", 6))    /* sendmail... */
  1811.         ;
  1812.       else if (*s == '>' || *s == ']')
  1813.         {
  1814.           line_is_citation = TRUE;
  1815.           XP_STRCPY(output_ptr, cite_open1);
  1816.           output_ptr += XP_STRLEN(cite_open1);
  1817.           XP_STRCPY(output_ptr, cite_open2);
  1818.           output_ptr += XP_STRLEN(cite_open2);
  1819.           if (CitationColor &&
  1820.               output_ptr + XP_STRLEN(CitationColor) + 20 < end_of_buffer) {
  1821.             XP_STRCPY(output_ptr, "<FONT COLOR=");
  1822.             output_ptr += XP_STRLEN(output_ptr);
  1823.             XP_STRCPY(output_ptr, CitationColor);
  1824.             output_ptr += XP_STRLEN(output_ptr);
  1825.             XP_STRCPY(output_ptr, ">");
  1826.             output_ptr += XP_STRLEN(output_ptr);
  1827.           }
  1828.         }
  1829.     }
  1830.  
  1831.   /* Normal lines are scanned for buried references to URL's
  1832.      Unfortunately, it may screw up once in a while (nobody's perfect)
  1833.    */
  1834.   for(cp = input; cp < end && output_ptr < end_of_buffer; cp++)
  1835.     {
  1836.       /* if NET_URL_Type returns true then it is most likely a URL
  1837.          But only match protocol names if at the very beginning of
  1838.          the string, or if the preceeding character was not alphanumeric;
  1839.          this lets us match inside "---HTTP://XXX" but not inside of
  1840.          things like "NotHTTP://xxx"
  1841.        */
  1842.       int type = 0;
  1843.       if(!XP_IS_SPACE(*cp) &&
  1844.          (cp == input || (!XP_IS_ALPHA(cp[-1]) && !XP_IS_DIGIT(cp[-1]))) &&
  1845.          (type = NET_URL_Type(cp)) != 0)
  1846.         {
  1847.           const char *cp2;
  1848.  
  1849.           for(cp2=cp; cp2 < end; cp2++)
  1850.             {
  1851.               /* These characters always mark the end of the URL. */
  1852.               if (XP_IS_SPACE(*cp2) ||
  1853.                   *cp2 == '<' || *cp2 == '>' ||
  1854.                   *cp2 == '`' || *cp2 == ')' ||
  1855.                   *cp2 == '\'' || *cp2 == '"' ||
  1856.                   *cp2 == ']' || *cp2 == '}') break;
  1857.             }
  1858.  
  1859.           /* Check for certain punctuation characters on the end, and strip
  1860.              them off. */
  1861.           while (cp2 > cp && 
  1862.                  (cp2[-1] == '.' || cp2[-1] == ',' || cp2[-1] == '!' ||
  1863.                   cp2[-1] == ';' || cp2[-1] == '-' || cp2[-1] == '?' ||
  1864.                   cp2[-1] == '#'))
  1865.             cp2--;
  1866.  
  1867.           col += (cp2 - cp);
  1868.  
  1869.           /* if the url is less than 7 characters then we screwed up
  1870.            * and got a "news:" url or something which is worthless
  1871.            * to us.  Exclude the A tag in this case.
  1872.            *
  1873.            * Also exclude any URL that ends in a colon; those tend
  1874.            * to be internal and magic and uninteresting.
  1875.            *
  1876.            * And also exclude the builtin icons, whose URLs look
  1877.            * like "internal-gopher-binary".
  1878.            */
  1879.           if (cp2-cp < 7 ||
  1880.               (cp2 > cp && cp2[-1] == ':') ||
  1881.               !XP_STRNCMP(cp, "internal-", 9))
  1882.             {
  1883.               XP_MEMCPY(output_ptr, cp, cp2-cp);
  1884.               output_ptr += (cp2-cp);
  1885.               *output_ptr = 0;
  1886.             }
  1887.           else
  1888.             {
  1889.               char *quoted_url;
  1890.               int32 size_left = output_size - (output_ptr-output);
  1891.  
  1892.               if(cp2-cp > size_left)
  1893.                 return MK_OUT_OF_MEMORY;
  1894.  
  1895.               XP_MEMCPY(output_ptr, cp, cp2-cp);
  1896.               output_ptr[cp2-cp] = 0;
  1897.               quoted_url = NET_EscapeHTML(output_ptr);
  1898.               if (!quoted_url) return MK_OUT_OF_MEMORY;
  1899.               PR_snprintf(output_ptr, size_left,
  1900.                           "<A HREF=\"%s\">%s</A>",
  1901.                           quoted_url,
  1902.                           quoted_url);
  1903.               output_ptr += XP_STRLEN(output_ptr);
  1904.               XP_FREE(quoted_url);
  1905.             }
  1906.  
  1907.           cp = cp2-1;  /* go to next word */
  1908.         }
  1909.       else
  1910.         {
  1911.           /* Make sure that special symbols don't screw up the HTML parser
  1912.            */
  1913.           if(*cp == '<')
  1914.             {
  1915.               XP_STRCPY(output_ptr, "<");
  1916.               output_ptr += 4;
  1917.               col++;
  1918.             }
  1919.           else if(*cp == '>')
  1920.             {
  1921.               XP_STRCPY(output_ptr, ">");
  1922.               output_ptr += 4;
  1923.               col++;
  1924.             }
  1925.           else if(*cp == '&')
  1926.             {
  1927.               XP_STRCPY(output_ptr, "&");
  1928.               output_ptr += 5;
  1929.               col++;
  1930.             }
  1931.           else
  1932.             {
  1933.               *output_ptr++ = *cp;
  1934.               col++;
  1935.             }
  1936.         }
  1937.     }
  1938.  
  1939.   *output_ptr = 0;
  1940.  
  1941.   if (line_is_citation)    /* Close off the highlighting */
  1942.     {
  1943.       if (CitationColor) {
  1944.         XP_STRCPY(output_ptr, "</FONT>");
  1945.         output_ptr += XP_STRLEN(output_ptr);
  1946.       }
  1947.  
  1948.       XP_STRCPY(output_ptr, cite_close2);
  1949.       output_ptr += XP_STRLEN (cite_close2);
  1950.       XP_STRCPY(output_ptr, cite_close1);
  1951.       output_ptr += XP_STRLEN (cite_close1);
  1952.     }
  1953.  
  1954.   return 0;
  1955. }
  1956.  
  1957.  
  1958. static void
  1959. Append(char** output, int32* output_max, char** curoutput, const char* buf,
  1960.        int32 length)
  1961. {
  1962.     if (length + (*curoutput) - (*output) >= *output_max) {
  1963.         int offset = (*curoutput) - (*output);
  1964.         do {
  1965.             (*output_max) += 1024;
  1966.         } while (length + (*curoutput) - (*output) >= *output_max);
  1967.         *output = XP_REALLOC(*output, *output_max);
  1968.         if (!*output) return;
  1969.         *curoutput = *output + offset;
  1970.     }
  1971.     XP_MEMCPY(*curoutput, buf, length);
  1972.     *curoutput += length;
  1973. }
  1974.  
  1975.  
  1976. char*
  1977. NET_ScanHTMLForURLs(const char* input)
  1978. {
  1979.     char* output = NULL;
  1980.     char* curoutput;
  1981.     int32 output_max;
  1982.     char* tmpbuf = NULL;
  1983.     int32 tmpbuf_max;
  1984.     int32 inputlength;
  1985.     const char* inputend;
  1986.     const char* linestart;
  1987.     const char* lineend;
  1988.  
  1989.     XP_ASSERT(input);
  1990.     if (!input) return NULL;
  1991.     inputlength = XP_STRLEN(input);
  1992.  
  1993.     output_max = inputlength + 1024; /* 1024 bytes ought to be enough to quote
  1994.                                         several URLs, which ought to be as many
  1995.                                         as most docs use. */
  1996.     output = XP_ALLOC(output_max);
  1997.     if (!output) goto FAIL;
  1998.  
  1999.     tmpbuf_max = 1024;
  2000.     tmpbuf = XP_ALLOC(tmpbuf_max);
  2001.     if (!tmpbuf) goto FAIL;
  2002.  
  2003.     inputend = input + inputlength;
  2004.  
  2005.     linestart = input;
  2006.     curoutput = output;
  2007.  
  2008.  
  2009.     /* Here's the strategy.  We find a chunk of plainish looking text -- no
  2010.        embedded CR or LF, no "<" or "&".  We feed that off to NET_ScanForURLs,
  2011.        and append the result.  Then we skip to the next bit of plain text.  If
  2012.        we stopped at an "&", go to the terminating ";".  If we stopped at a
  2013.        "<", well, if it was a "<A>" tag, then skip to the closing "</A>".
  2014.        Otherwise, skip to the end of the tag.
  2015.        */
  2016.  
  2017.  
  2018.     lineend = linestart;
  2019.     while (linestart < inputend && lineend <= inputend) {
  2020.         switch (*lineend) {
  2021.         case '<':
  2022.         case '>':
  2023.         case '&':
  2024.         case CR:
  2025.         case LF:
  2026.         case '\0':
  2027.             if (lineend > linestart) {
  2028.                 int length = lineend - linestart;
  2029.                 if (length * 3 > tmpbuf_max) {
  2030.                     tmpbuf_max = length * 3 + 512;
  2031.                     XP_FREE(tmpbuf);
  2032.                     tmpbuf = XP_ALLOC(tmpbuf_max);
  2033.                     if (!tmpbuf) goto FAIL;
  2034.                 }
  2035.                 if (NET_ScanForURLs(NULL, linestart, length,
  2036.                                     tmpbuf, tmpbuf_max, TRUE) < 0) {
  2037.                     goto FAIL;
  2038.                 }
  2039.                 length = XP_STRLEN(tmpbuf);
  2040.                 Append(&output, &output_max, &curoutput, tmpbuf, length);
  2041.                 if (!output) goto FAIL;
  2042.  
  2043.             }
  2044.             linestart = lineend;
  2045.             lineend = NULL;
  2046.             if (inputend - linestart < 5) {
  2047.                 /* Too little to worry about; shove the rest out. */
  2048.                 lineend = inputend;
  2049.             } else {
  2050.                 switch (*linestart) {
  2051.                 case '<':
  2052.                     if ((linestart[1] == 'a' || linestart[1] == 'A') &&
  2053.                         linestart[2] == ' ') {
  2054.                         lineend = strcasestr(linestart, "</a");
  2055.                         if (lineend) {
  2056.                             lineend = XP_STRCHR(lineend, '>');
  2057.                             if (lineend) lineend++;
  2058.                         }
  2059.                     } else {
  2060.                         lineend = XP_STRCHR(linestart, '>');
  2061.                         if (lineend) lineend++;
  2062.                     }
  2063.                     break;
  2064.                 case '&':
  2065.                     lineend = XP_STRCHR(linestart, ';');
  2066.                     if (lineend) lineend++;
  2067.                     break;
  2068.                 default:
  2069.                     lineend = linestart + 1;
  2070.                     break;
  2071.                 }
  2072.             }
  2073.             if (!lineend) lineend = inputend;
  2074.             Append(&output, &output_max, &curoutput, linestart,
  2075.                    lineend - linestart);
  2076.             if (!output) goto FAIL;
  2077.             linestart = lineend;
  2078.             break;
  2079.         default:
  2080.             lineend++;
  2081.         }
  2082.     }
  2083.     XP_FREE(tmpbuf);
  2084.     *curoutput = '\0';
  2085.     return output;
  2086.  
  2087. FAIL:
  2088.     if (tmpbuf) XP_FREE(tmpbuf);
  2089.     if (output) XP_FREE(output);
  2090.     return NULL;
  2091. }
  2092.  
  2093.  
  2094. /* try to make sure that this is a fully qualified
  2095.  * email address including a host and domain
  2096.  */
  2097. PUBLIC Bool 
  2098. NET_IsFQDNMailAddress(const char * string)
  2099. {
  2100.     /* first make sure that an @ exists
  2101.      */
  2102.     char * at_sign = XP_STRCHR(string, '@');
  2103.  
  2104.     if(at_sign)
  2105.       {
  2106.         /* make sure it has at least one period 
  2107.          */
  2108.         if(XP_STRCHR(at_sign, '.'))
  2109.             return(TRUE);
  2110.       }
  2111.  
  2112.     return(FALSE);
  2113. }
  2114.  
  2115. static int use_ssl_for_imap4 = -1; /* -1 if uninitialized, 0 if FALSE, 1 if TRUE. */
  2116.  
  2117. /* fix Mac warning about missing prototype */
  2118. MODULE_PRIVATE int PR_CALLBACK net_use_ssl_for_imap4_changed_func(const char *pref,
  2119.                                                                   void *data);
  2120.  
  2121. MODULE_PRIVATE int PR_CALLBACK net_use_ssl_for_imap4_changed_func(const char *pref,
  2122.                                                                   void *data) 
  2123. {
  2124.     int status = PREF_NOERROR;
  2125.  
  2126.     if (!XP_STRCASECMP(pref,"mail.imap.server_ssl")) {
  2127.         XP_Bool    new_val;
  2128.  
  2129.         status = PREF_GetBoolPref("mail.imap.server_ssl", &new_val);
  2130.         use_ssl_for_imap4 = (int)new_val;
  2131.     }
  2132.     return status;
  2133. }
  2134.  
  2135.  
  2136. /* returns true if the URL is a secure URL address
  2137.  */
  2138. PUBLIC Bool
  2139. NET_IsURLSecure(char * address)
  2140. {
  2141.    int type = NET_URL_Type (address);
  2142.  
  2143.    TRACEMSG(("NET_IsURLSecure called, type: %d", type));
  2144.  
  2145.     if(type == SECURE_HTTP_TYPE_URL
  2146.         || type == INTERNAL_IMAGE_TYPE_URL
  2147.         || type == SECURE_LDAP_TYPE_URL)
  2148.         return(TRUE);
  2149.  
  2150.     if(!strncasecomp(address, "/mc-icons/", 10) ||
  2151.        !strncasecomp(address, "/ns-icons/", 10))
  2152.         return(TRUE);
  2153.  
  2154.     if(!strncasecomp(address, "internal-external-reconnect:", 28))
  2155.         return(TRUE);
  2156.  
  2157.     if(!strcasecomp(address, "internal-external-plugin"))
  2158.         return(TRUE);
  2159.  
  2160.     if(!strncasecomp(address, "snews:", 6))
  2161.         return TRUE;
  2162.  
  2163.         /*
  2164.          * IMAP URLs begin with "mailbox://" unlike POP URLs which begin
  2165.          * with "mailbox:".
  2166.          */
  2167.     if(!strncasecomp(address, "mailbox://", 10)) {
  2168.         if (use_ssl_for_imap4 < 0) { /* If uninitialized. */
  2169.             XP_Bool new_val;
  2170.             int status = PREF_GetBoolPref("mail.imap.server_ssl", &new_val);
  2171.  
  2172.             if (status == PREF_NOERROR) {
  2173.                 use_ssl_for_imap4 = (int)new_val;
  2174.                 PREF_RegisterCallback("mail.imap.server_ssl",
  2175.                                       net_use_ssl_for_imap4_changed_func, NULL);
  2176.             }
  2177.             else {
  2178.                 return FALSE;
  2179.             }
  2180.         }
  2181.         return (Bool)use_ssl_for_imap4;
  2182.     }
  2183.  
  2184.     
  2185.     TRACEMSG(("NET_IsURLSecure: URL NOT SECURE"));
  2186.  
  2187.     return(FALSE);
  2188. }
  2189.  
  2190. /* escapes all '<', '>' and '&' characters in a string
  2191.  * returns a string that must be freed
  2192.  */
  2193. PUBLIC char *
  2194. NET_EscapeHTML(const char * string)
  2195. {
  2196.     char *rv = (char *) XP_ALLOC(XP_STRLEN(string)*4 + 1); /* The +1 is for
  2197.                                                               the trailing
  2198.                                                               null! */
  2199.     char *ptr = rv;
  2200.  
  2201.     if(rv)
  2202.       {
  2203.         for(; *string != '\0'; string++)
  2204.           {
  2205.             if(*string == '<')
  2206.               {
  2207.                 *ptr++ = '&';
  2208.                 *ptr++ = 'l';
  2209.                 *ptr++ = 't';
  2210.                 *ptr++ = ';';
  2211.               }
  2212.             else if(*string == '>')
  2213.               {
  2214.                 *ptr++ = '&';
  2215.                 *ptr++ = 'g';
  2216.                 *ptr++ = 't';
  2217.                 *ptr++ = ';';
  2218.               }
  2219.             else if(*string == '&')
  2220.               {
  2221.                 *ptr++ = '&';
  2222.                 *ptr++ = 'a';
  2223.                 *ptr++ = 'm';
  2224.                 *ptr++ = 'p';
  2225.                 *ptr++ = ';';
  2226.               }
  2227.             else
  2228.               {
  2229.                 *ptr++ = *string;
  2230.               }
  2231.           }
  2232.         *ptr = '\0';
  2233.       }
  2234.  
  2235.     return(rv);
  2236. }
  2237.  
  2238.  
  2239. PUBLIC char *
  2240. NET_SpaceToPlus(char * string)
  2241. {
  2242.  
  2243.     char * ptr = string;
  2244.  
  2245.     if(!ptr)
  2246.         return(NULL);
  2247.  
  2248.     for(; *ptr != '\0'; ptr++)
  2249.         if(*ptr == ' ')
  2250.             *ptr = '+';
  2251.  
  2252.     return(string);
  2253. }
  2254.  
  2255.  
  2256. /* returns true if the functions thinks the string contains
  2257.  * HTML
  2258.  */
  2259. PUBLIC Bool
  2260. NET_ContainsHTML(char * string, int32 length)
  2261. {
  2262.     char * ptr = string;
  2263.     register int32 count=length;
  2264.  
  2265.     /* restrict searching to first K to limit false positives */
  2266.     if(count > 1024)
  2267.         count = 1024;
  2268.  
  2269.     /* if the string begins with "#!" or "%!" then it's a script of some kind,
  2270.        and it doesn't matter how many HTML tags that program references in its
  2271.        source -- it ain't HTML.  This false match happened all the time with,
  2272.        for example, CGI scripts written in sh or perl that emit HTML. */
  2273.     if (count > 2 &&
  2274.         (string[0] == '#' || string[0] == '%') &&
  2275.         string[1] == '!')
  2276.       return FALSE;
  2277.  
  2278.     /* If it begins with a mailbox delimiter, it's not HTML. */
  2279.     if (count > 5 &&
  2280.         (!XP_STRNCMP(string, "From ", 5) ||
  2281.          !XP_STRNCMP(string, ">From ", 6)))
  2282.       return FALSE;
  2283.  
  2284.     for(; count > 0; ptr++, count--)
  2285.         if(*ptr == '<')
  2286.           {
  2287.             if(count > 3 && !strncasecomp(ptr+1, "HTML", 4))
  2288.                 return(TRUE);
  2289.  
  2290.             if(count > 4 && !strncasecomp(ptr+1, "TITLE", 5))
  2291.                 return(TRUE);
  2292.         
  2293.             if(count > 3 && !strncasecomp(ptr+1, "FRAMESET", 8))
  2294.                 return(TRUE);
  2295.  
  2296.             if(count > 2 && 
  2297.                 toupper(*(ptr+1)) == 'H' 
  2298.                         && isdigit(*(ptr+2)) && *(ptr+3) == '>')
  2299.                 return(TRUE);
  2300.           }
  2301.  
  2302.     return(FALSE);
  2303. }
  2304.  
  2305. /* take a Layout generated LO_FormSubmitData_struct
  2306.  * and use it to add post data to the URL Structure
  2307.  * generated by CreateURLStruct
  2308.  *
  2309.  * DOES NOT Generate the URL Struct, it must be created prior to
  2310.  * calling this function
  2311.  *
  2312.  * returns 0 on failure and 1 on success
  2313.  */
  2314.  
  2315. PUBLIC int
  2316. NET_AddLOSubmitDataToURLStruct(LO_FormSubmitData * sub_data, 
  2317.                                URL_Struct * url_struct)
  2318. {
  2319.  
  2320.     int32 i;
  2321.     int32 total_size;
  2322.     char *end, *tmp_ptr;
  2323.     char *encoding;
  2324.     char *target;
  2325.     char **name_array;
  2326.     char **value_array;
  2327.     uint8 *type_array;
  2328.     uint8 *encoding_array;
  2329.     char *esc_string;
  2330.     int32 len = 0;
  2331.  
  2332.     if(!sub_data || !url_struct)
  2333.         return(0);
  2334.  
  2335.     if(sub_data->method == FORM_METHOD_GET)
  2336.         url_struct->method = URL_GET_METHOD;
  2337.     else
  2338.         url_struct->method = URL_POST_METHOD;
  2339.     if (!strncasecomp(url_struct->address, "mailto:", 7)) {
  2340.         url_struct->mailto_post = TRUE;
  2341.     }
  2342.  
  2343.     /* free any previous url_struct->post_data
  2344.      */
  2345.     FREEIF(url_struct->post_data);
  2346.  
  2347.     PA_LOCK(name_array,  char**, sub_data->name_array);
  2348.     PA_LOCK(value_array, char**, sub_data->value_array);
  2349.     PA_LOCK(type_array,  uint8*, sub_data->type_array);
  2350.     PA_LOCK(encoding_array, uint8*, sub_data->encoding_array);
  2351.     PA_LOCK(encoding, char*, sub_data->encoding);
  2352.  
  2353.     /* free any previous target
  2354.      */
  2355.     FREEIF(url_struct->window_target);
  2356.     PA_LOCK(target, char*, sub_data->window_target);
  2357.     if (target == NULL)
  2358.         url_struct->window_target = NULL;
  2359.     else
  2360.         url_struct->window_target = XP_STRDUP (target);
  2361.  
  2362.     FREEIF (url_struct->post_headers);
  2363.  
  2364.     /* If we're posting to mailto, then generate the full complement
  2365.        of mail headers; and allow the url to specify additional headers
  2366.        as well. */
  2367. #ifdef MOZ_MAIL_NEWS    
  2368.     if (!strncasecomp(url_struct->address, "mailto:", 7))
  2369.       {
  2370. #ifdef MOZILLA_CLIENT
  2371.         int status;
  2372.         char *new_url = 0;
  2373.         char *headers = 0;
  2374.  
  2375.         status = MIME_GenerateMailtoFormPostHeaders (url_struct->address,
  2376.                                                      url_struct->referer,
  2377.                                                      &new_url, &headers);
  2378.         if (status < 0)
  2379.           {
  2380.             FREEIF (new_url);
  2381.             FREEIF (headers);
  2382.             return status;
  2383.           }
  2384.         XP_ASSERT (new_url);
  2385.         XP_ASSERT (headers);
  2386.         url_struct->address_modified = TRUE;
  2387.         XP_FREE (url_struct->address);
  2388.         url_struct->address = new_url;
  2389.         url_struct->post_headers = headers;
  2390. #else
  2391.         XP_ASSERT(0);
  2392. #endif /* MOZILLA_CLIENT */
  2393.       }
  2394. #endif /* MOZ_MAIL_NEWS */
  2395.  
  2396.     if(encoding && !strcasecomp(encoding, "text/plain"))
  2397.       {
  2398.         char *tmpfilename;
  2399.         char buffer[512];
  2400.         XP_File fp;
  2401.  
  2402.         /* always use post for this encoding type
  2403.          */
  2404.         url_struct->method = URL_POST_METHOD;
  2405.  
  2406.         /* write all the post data to a file first
  2407.          * so that we can send really big stuff
  2408.          */
  2409. #ifdef XP_MAC    /* This should really be for all platforms but I am fixing a bug for final release */
  2410.           tmpfilename = WH_TempName (xpFileToPost, "nsform");
  2411.         if (!tmpfilename) return 0;
  2412.           fp = XP_FileOpen (tmpfilename, xpFileToPost, XP_FILE_WRITE_BIN);
  2413. #else
  2414.           tmpfilename = WH_TempName (xpTemporary, "nsform");
  2415.         if (!tmpfilename) return 0;
  2416.           fp = XP_FileOpen (tmpfilename, xpTemporary, XP_FILE_WRITE_BIN);
  2417. #endif
  2418.           if (!fp) {
  2419.             XP_FREE(tmpfilename);
  2420.             return 0;
  2421.         }
  2422.  
  2423.         if (url_struct->post_headers)
  2424.           {
  2425.             len = XP_FileWrite(url_struct->post_headers,
  2426.                          XP_STRLEN (url_struct->post_headers),
  2427.                          fp);
  2428.             XP_FREE (url_struct->post_headers);
  2429.             url_struct->post_headers = 0;
  2430.             if (len < 0)
  2431.             {
  2432.                 XP_FileClose(fp);
  2433.                 return 0;
  2434.             }
  2435.           }
  2436.  
  2437.         XP_STRCPY (buffer,
  2438.                    "Content-type: text/plain" CRLF
  2439.                    "Content-Disposition: inline; form-data" CRLF CRLF);
  2440.         len = XP_FileWrite(buffer, XP_STRLEN(buffer), fp);
  2441.  
  2442.         for(i=0; (len >= 0) && (i < sub_data->value_cnt); i++)
  2443.           {
  2444.             if(name_array[i])
  2445.                 XP_FileWrite(name_array[i], XP_STRLEN(name_array[i]), fp);
  2446.             XP_FileWrite("=", 1, fp);
  2447.             if(value_array[i])
  2448.                 XP_FileWrite(value_array[i], XP_STRLEN(value_array[i]), fp);
  2449.             len = XP_FileWrite(CRLF, 2, fp);
  2450.           }
  2451.         XP_FileClose(fp);
  2452.     
  2453.         StrAllocCopy(url_struct->post_data, tmpfilename);
  2454.         XP_FREE(tmpfilename);
  2455.         if (len < 0)
  2456.             return 0;
  2457.         url_struct->post_data_is_file = TRUE;
  2458.       }
  2459.     else if(encoding && !strcasecomp(encoding, "multipart/form-data"))
  2460.       {
  2461.         /* encoding using a variant of multipart/mixed
  2462.            * and add files to it as well
  2463.          */
  2464.         char *tmpfilename;
  2465.         char separator[80];
  2466.         char buffer[512];
  2467.         XP_File fp;
  2468.         int boundary_len;
  2469.         int cont_disp_len;
  2470.         NET_cinfo * ctype;
  2471.  
  2472.  
  2473.         /* always use post for this encoding type
  2474.          */
  2475.         url_struct->method = URL_POST_METHOD;
  2476.  
  2477.         /* write all the post data to a file first
  2478.          * so that we can send really big stuff
  2479.          */
  2480.           tmpfilename = WH_TempName (xpFileToPost, "nsform");
  2481.         if (!tmpfilename) return 0;
  2482.           fp = XP_FileOpen (tmpfilename, xpFileToPost, XP_FILE_WRITE_BIN);
  2483.           if (!fp) {
  2484.             XP_FREE(tmpfilename);
  2485.             return 0;
  2486.         }
  2487.  
  2488.         sprintf(separator, "---------------------------%d%d%d",
  2489.                 rand(), rand(), rand());
  2490.  
  2491.         if(url_struct->post_headers)
  2492.           {
  2493.             len = XP_FileWrite(url_struct->post_headers,
  2494.                          XP_STRLEN (url_struct->post_headers),
  2495.                          fp);
  2496.             XP_FREE (url_struct->post_headers);
  2497.             url_struct->post_headers = 0;
  2498.             if (len < 0)
  2499.                 return 0;
  2500.           }
  2501.  
  2502.         sprintf(buffer,
  2503.                 "Content-type: multipart/form-data;"
  2504.                 " boundary=%s" CRLF,
  2505.                 separator);
  2506.         len = XP_FileWrite(buffer, XP_STRLEN(buffer), fp);
  2507.  
  2508. #define CONTENT_DISPOSITION "Content-Disposition: form-data; name=\""
  2509. #define PLUS_FILENAME "\"; filename=\""
  2510. #define CONTENT_TYPE_HEADER "Content-Type: "
  2511. #define CONTENT_ENCODING_HEADER "Content-Encoding: "
  2512.  
  2513.         /* compute the content length */
  2514.         total_size = -2; /* start at negative 2 to disregard the
  2515.                           * CRLF that act as a header separator 
  2516.                           */
  2517.         boundary_len = XP_STRLEN(separator) + 6;
  2518.         cont_disp_len = XP_STRLEN(CONTENT_DISPOSITION);
  2519.  
  2520.         for(i=0; (len >= 0) && (i < sub_data->value_cnt); i++)
  2521.           {
  2522.             total_size += boundary_len;
  2523.  
  2524.             /* The size of the content-disposition line is hard
  2525.              * coded and must be modified any time you change
  2526.              * the sprintf in the next for loop
  2527.              */
  2528.             total_size += cont_disp_len;
  2529.             if(name_array[i])
  2530.                 total_size += XP_STRLEN(name_array[i]);
  2531.             total_size += 5;  /* quote plus two CRLF's */
  2532.  
  2533.             if(type_array[i] == FORM_TYPE_FILE)
  2534.               {
  2535.                 XP_StatStruct stat_entry;
  2536.  
  2537.                 /* in this case we are going to send an extra
  2538.                  * ; filename="value_array[i]"
  2539.                  */
  2540.                 total_size += XP_STRLEN(PLUS_FILENAME);
  2541.                 if(value_array[i])
  2542.                 {
  2543.                     /* only write the filename, not the whole path */
  2544.                     char * slash = XP_STRRCHR(value_array[i], '/');
  2545.                     if(slash)
  2546.                         slash++;
  2547.                     else
  2548.                         slash = value_array[i];
  2549.                     total_size += XP_STRLEN(slash);
  2550.  
  2551. #ifdef XP_MAC
  2552.                     if(encoding_array[i] == INPUT_TYPE_ENCODING_MACBIN)
  2553.                     {
  2554.                         /* add the size of the content type header */
  2555.                         /* NOTE - even though MacBinary is technically an encoding type we send
  2556.                                   it as a content type and skip the normal routine of trying
  2557.                                   to determine the actual file type
  2558.                         */
  2559.                         total_size += sizeof(CONTENT_TYPE_HEADER)-1;
  2560.                         total_size += sizeof(APPLICATION_MACBINARY)-1;
  2561.                         total_size += 2;  /* for the CRLF terminator */
  2562.                     }
  2563.                     else
  2564. #endif /* XP_MAC */
  2565.                     {
  2566.  
  2567.                         /* try and determine the content-type of the file
  2568.                          */
  2569.                         ctype = NET_cinfo_find_type(value_array[i]);
  2570.  
  2571.                         if(!ctype->is_default)
  2572.                         {
  2573.                             /* we have determined it's type. Add enough
  2574.                              * space for it
  2575.                              */
  2576.                             total_size += sizeof(CONTENT_TYPE_HEADER)-1;
  2577.                             total_size += XP_STRLEN(ctype->type);
  2578.                             total_size += 2;  /* for the CRLF terminator */
  2579.                         }
  2580.                     }
  2581.                 }
  2582. #ifdef XP_MAC
  2583.                 if(encoding_array[i] == INPUT_TYPE_ENCODING_MACBIN)
  2584.                 {
  2585.                     /* figure out the size of the macbinary encoded file
  2586.                      * and add it to total_size
  2587.                      */
  2588.                     if(value_array[i] && *value_array[i])
  2589.                         if(-1 != MB_Stat (value_array[i], &stat_entry, xpFileToPost))
  2590.                             total_size += stat_entry.st_size;
  2591.                 }
  2592.                 else
  2593. #endif /* XP_MAC */
  2594.                 {
  2595.                     /* if the type is a FILE type then we 
  2596.                      * need to stat the file to get the size
  2597.                      */
  2598.                     if(value_array[i] && *value_array[i])
  2599.                         if(-1 != XP_Stat (value_array[i], &stat_entry, xpFileToPost))
  2600.                             total_size += stat_entry.st_size;
  2601.  
  2602.                     /* if we can't stat the file just add zero */
  2603.                 }
  2604.               }
  2605.             else
  2606.               {
  2607.                 if(value_array[i])
  2608.                     total_size += XP_STRLEN(value_array[i]);
  2609.               }
  2610.           }
  2611.         /* add the size of the last separator plus
  2612.          * two for the extra two dashes
  2613.          */
  2614.         total_size += boundary_len+2;
  2615.  
  2616.         sprintf(buffer, "Content-Length: %ld%s", total_size, CRLF);
  2617.         len = XP_FileWrite(buffer, XP_STRLEN(buffer), fp);
  2618.  
  2619.         for(i=0; (len >= 0) && (i < sub_data->value_cnt); i++)
  2620.           {
  2621.             sprintf(buffer, "%s--%s%s", CRLF, separator, CRLF);
  2622.             XP_FileWrite(buffer, XP_STRLEN(buffer), fp);
  2623.             
  2624.             /* WARNING!!! If you change the size of any of the
  2625.              * sprintf's here you must change the size
  2626.              * in the counting for loop above
  2627.              */
  2628.             XP_FileWrite(CONTENT_DISPOSITION, cont_disp_len, fp);
  2629.             if(name_array[i])
  2630.                 XP_FileWrite(name_array[i], XP_STRLEN(name_array[i]), fp);
  2631.  
  2632.             if(type_array[i] == FORM_TYPE_FILE)
  2633.               {
  2634.                 XP_FileWrite(PLUS_FILENAME, XP_STRLEN(PLUS_FILENAME), fp);
  2635.                 if(value_array[i])
  2636.                   {
  2637.                     /* only write the filename, not the whole path */
  2638.                     char * slash = XP_STRRCHR(value_array[i], '/');
  2639.                     if(slash)
  2640.                         slash++;
  2641.                     else
  2642.                         slash = value_array[i];
  2643.                     XP_FileWrite(slash, XP_STRLEN(slash), fp);
  2644.  
  2645.                   }
  2646.               }
  2647.               /* end the content disposition line */
  2648.             len = XP_FileWrite("\"" CRLF, XP_STRLEN("\"" CRLF), fp);
  2649.  
  2650.             if(type_array[i] == FORM_TYPE_FILE && value_array[i])
  2651.             {
  2652. #ifdef XP_MAC
  2653.                 if(encoding_array[i] == INPUT_TYPE_ENCODING_MACBIN)
  2654.                 {
  2655.                     /* add the content_type header */
  2656.                     XP_FileWrite(CONTENT_TYPE_HEADER, 
  2657.                                          XP_STRLEN(CONTENT_TYPE_HEADER),
  2658.                                          fp);
  2659.                     XP_FileWrite(APPLICATION_MACBINARY, 
  2660.                                          XP_STRLEN(APPLICATION_MACBINARY),
  2661.                                          fp);
  2662.                     len = XP_FileWrite(CRLF, XP_STRLEN(CRLF), fp);
  2663.                 }
  2664.                 else
  2665. #endif /* XP_MAC */
  2666.                 {
  2667.                     /* try and determine the content-type of the file
  2668.                       */
  2669.                     ctype = NET_cinfo_find_type(value_array[i]);
  2670.  
  2671.                     if(!ctype->is_default)
  2672.                     {
  2673.                         /* we have determined it's type. Send the
  2674.                          * content-type
  2675.                          */
  2676.                         XP_FileWrite(CONTENT_TYPE_HEADER, 
  2677.                                              XP_STRLEN(CONTENT_TYPE_HEADER),
  2678.                                              fp);
  2679.                         XP_FileWrite(ctype->type,
  2680.                                              XP_STRLEN(ctype->type),
  2681.                                              fp);
  2682.                         len = XP_FileWrite(CRLF, XP_STRLEN(CRLF), fp);
  2683.                     }
  2684.                 }
  2685.             }
  2686.  
  2687.             /* end the header */
  2688.             len = XP_FileWrite(CRLF, XP_STRLEN(CRLF), fp);
  2689.  
  2690.             /* send the value of the form field */
  2691.  
  2692.             /* if the type is a FILE type, send the whole file,
  2693.              * the filename is in the value field
  2694.              */
  2695.             if(type_array[i] == FORM_TYPE_FILE)
  2696.               {
  2697. #ifdef XP_MAC
  2698.                 if(encoding_array[i] == INPUT_TYPE_ENCODING_MACBIN)
  2699.                 {
  2700.                     MB_FileSpec    mbFile;
  2701.                     int32        size;
  2702.                     OSErr        theErr;
  2703.                     
  2704.                     if (value_array[i] && *value_array[i])
  2705.                     {
  2706.                         theErr = MB_Open(value_array[i], &mbFile);
  2707.  
  2708.                         if (theErr == noErr)
  2709.                           {
  2710.                             while((size = MB_Read(NET_Socket_Buffer, 
  2711.                                                         NET_Socket_Buffer_Size, 
  2712.                                                         &mbFile)) != 0)
  2713.                               {
  2714.                                 XP_FileWrite(NET_Socket_Buffer, size, fp);
  2715.                               }
  2716.                             MB_Close(&mbFile);
  2717.                           }
  2718.                     }
  2719.                 }
  2720.                 else
  2721. #endif /* XP_MAC */
  2722.                 {
  2723.                     XP_File ext_fp=0;
  2724.                     int32 size;
  2725.  
  2726.                     if(value_array[i] && *value_array[i])
  2727.                         ext_fp = XP_FileOpen(value_array[i], 
  2728.                                          xpFileToPost, 
  2729.                                          XP_FILE_READ_BIN);
  2730.  
  2731.  
  2732.                     if(ext_fp)
  2733.                       {
  2734.                         while((size = XP_FileRead(NET_Socket_Buffer, 
  2735.                                                     NET_Socket_Buffer_Size, 
  2736.                                                     ext_fp)) != 0)
  2737.                           {
  2738.                             XP_FileWrite(NET_Socket_Buffer, size, fp);
  2739.                           }
  2740.                         XP_FileClose(ext_fp);
  2741.                       }
  2742.                  }
  2743.               }
  2744.             else
  2745.               {
  2746.                 if(value_array[i])
  2747.                     XP_FileWrite(value_array[i], XP_STRLEN(value_array[i]), fp);
  2748.               }
  2749.           }
  2750.  
  2751.         sprintf(buffer, "%s--%s--%s", CRLF, separator, CRLF);
  2752.         XP_FileWrite(buffer, XP_STRLEN(buffer), fp);
  2753.  
  2754.         XP_FileClose(fp);
  2755.     
  2756.         StrAllocCopy(url_struct->post_data, tmpfilename);
  2757.         XP_FREE(tmpfilename);
  2758.         url_struct->post_data_is_file = TRUE;
  2759.  
  2760.       }
  2761.     else
  2762.       {
  2763.         total_size=1; /* start at one for the terminator char */
  2764.  
  2765.         /* find out how much space we need total
  2766.          *
  2767.          * and also convert all spaces to pluses at the same time
  2768.           */
  2769.         for(i=0; i<sub_data->value_cnt; i++)
  2770.           {
  2771.             total_size += NET_EscapedSize(name_array[i], URL_XPALPHAS);
  2772.             total_size += NET_EscapedSize(value_array[i], URL_XPALPHAS);
  2773.             total_size += 2;  /* & = */
  2774.           }
  2775.  
  2776.         if(sub_data->method == FORM_METHOD_GET)
  2777.           {
  2778.             char *punc;
  2779.  
  2780.             if(!url_struct->address)
  2781.                 return(0);
  2782.  
  2783.             /* get rid of ? or # in the url string since we are adding it
  2784.              */
  2785.             punc = XP_STRCHR(url_struct->address, '?');
  2786.             if(punc)
  2787.                *punc = '\0';  /* terminate here */
  2788.             punc = XP_STRCHR(url_struct->address, '#');
  2789.             if(punc)
  2790.                *punc = '\0';  /* terminate here */
  2791.  
  2792.             /* add the size of the url plus one for the '?'
  2793.              */
  2794.             total_size += XP_STRLEN(url_struct->address)+1;
  2795.           }
  2796.  
  2797.         url_struct->post_data = (char *) XP_ALLOC(total_size);
  2798.  
  2799.         if(!url_struct->post_data)
  2800.           {
  2801.             PA_UNLOCK(sub_data->name_array);
  2802.             PA_UNLOCK(sub_data->value_array);
  2803.             PA_UNLOCK(sub_data->type_array);
  2804.             PA_UNLOCK(sub_data->encoding);
  2805.             return(0);
  2806.           }
  2807.  
  2808.         if(sub_data->method == FORM_METHOD_GET)
  2809.           {
  2810.               end = url_struct->post_data;
  2811.             for(tmp_ptr = url_struct->address; *tmp_ptr != '\0'; tmp_ptr++)
  2812.                 *end++ = *tmp_ptr;
  2813.  
  2814.             /* add the '?'
  2815.              */
  2816.             *end++ = '?';
  2817.  
  2818.             /* swap the post data and address data */
  2819.             FREE(url_struct->address);
  2820.             url_struct->address = url_struct->post_data;
  2821.             url_struct->post_data = 0;
  2822.  
  2823.             /* perform  hack:
  2824.              * To be compatible with old pre-form 
  2825.              * indexes, other web browsers had a hack
  2826.              * wherein if a form was being submitted, 
  2827.              * and its method was get, and it
  2828.              * had only one name/value pair, and the 
  2829.              * name of that pair was "isindex", then
  2830.              * it would create the query url
  2831.              *
  2832.              * URL?value instead of URL?name=value
  2833.              */
  2834.             if(sub_data->value_cnt == 1 && !strcasecomp(name_array[0], "isindex"))
  2835.               {
  2836.                 if(value_array && value_array[0])
  2837.                     XP_STRCPY(end, NET_Escape(value_array[0], URL_XPALPHAS));
  2838.                 else
  2839.                     *end = '\0';
  2840.                 PA_UNLOCK(sub_data->name_array);
  2841.                 PA_UNLOCK(sub_data->value_array);
  2842.                 PA_UNLOCK(sub_data->type_array);
  2843.                 PA_UNLOCK(sub_data->encoding);
  2844.                 return(1);
  2845.               }
  2846.             
  2847.             /* the end ptr is still set to the correct address!
  2848.              */
  2849.  
  2850.           }
  2851.         else
  2852.           {
  2853.             StrAllocCat(url_struct->post_headers,
  2854.                         "Content-type: application/x-www-form-urlencoded" CRLF);
  2855.     
  2856.             if(!url_struct->post_headers)
  2857.               {
  2858.                 FREE_AND_CLEAR(url_struct->post_data);
  2859.                 PA_UNLOCK(sub_data->name_array);
  2860.                 PA_UNLOCK(sub_data->value_array);
  2861.                 PA_UNLOCK(sub_data->type_array);
  2862.                 PA_UNLOCK(sub_data->encoding);
  2863.                 return(0);
  2864.               }
  2865.  
  2866.               end = url_struct->post_data;
  2867.  
  2868.           }
  2869.  
  2870.         /* build the string 
  2871.          */
  2872.         for(i=0; i<sub_data->value_cnt; i++)
  2873.           {
  2874.             /* add the name
  2875.              */
  2876.             esc_string = NET_Escape(name_array[i], URL_XPALPHAS);
  2877.             if(esc_string)
  2878.               {
  2879.                 for(tmp_ptr = esc_string; *tmp_ptr != '\0'; tmp_ptr++)
  2880.                     *end++ = *tmp_ptr;
  2881.                 XP_FREE(esc_string);
  2882.               }
  2883.  
  2884.             /* join the name and value with a '='
  2885.               */
  2886.             *end++ = '=';
  2887.  
  2888.             /* add the value
  2889.              */
  2890.             esc_string = NET_Escape(value_array[i], URL_XPALPHAS);
  2891.             if(esc_string)
  2892.               {
  2893.                 for(tmp_ptr = esc_string; *tmp_ptr != '\0'; tmp_ptr++)
  2894.                     *end++ = *tmp_ptr;
  2895.                 XP_FREE(esc_string);
  2896.               }
  2897.  
  2898.             /* join pairs with a '&' 
  2899.              * make sure there is another pair before adding
  2900.              */
  2901.             if(i+1 < sub_data->value_cnt)
  2902.                 *end++ = '&';
  2903.           }
  2904.         
  2905.         /* terminate the string
  2906.          */
  2907.         *end = '\0';
  2908.  
  2909.         if(sub_data->method == FORM_METHOD_POST)
  2910.           {
  2911.             char buffer[64];
  2912.             url_struct->post_data_size = XP_STRLEN(url_struct->post_data);
  2913.             XP_SPRINTF(buffer, 
  2914.                        "Content-length: %ld" CRLF, 
  2915.                        url_struct->post_data_size);
  2916.             StrAllocCat(url_struct->post_headers, buffer);
  2917.  
  2918. #ifdef ADD_EXTRA_CRLF_TO_POSTS
  2919.             /* munge for broken CGIs.  Add an extra CRLF to the 
  2920.              * post data.
  2921.              */
  2922.             BlockAllocCat(url_struct->post_data, 
  2923.                           url_struct->post_data_size,
  2924.                           CRLF, 
  2925.                           3);
  2926.             /* don't add the eol terminator */
  2927.             url_struct->post_data_size += 2;
  2928. #endif /* ADD_EXTRA_CRLF_TO_POSTS */
  2929.  
  2930.           }
  2931.       }
  2932.  
  2933.     PA_UNLOCK(sub_data->name_array);
  2934.     PA_UNLOCK(sub_data->value_array);
  2935.     PA_UNLOCK(sub_data->type_array);
  2936.     PA_UNLOCK(sub_data->encoding);
  2937.  
  2938.     return(1); /* success */
  2939. }
  2940.  
  2941. PUBLIC int
  2942. NET_AddCoordinatesToURLStruct(URL_Struct * url_struct, int32 x_coord, int32 y_coord)
  2943. {
  2944.  
  2945.     if(url_struct->address)
  2946.       {
  2947.         char buffer[32];
  2948.  
  2949.         XP_SPRINTF(buffer, "?%ld,%ld", x_coord, y_coord);
  2950.  
  2951.         /* get rid of ? or # in the url string since we are adding it
  2952.          */
  2953. #undef STRIP_SEARCH_DATA_FROM_ISMAP_URLS
  2954. #ifdef STRIP_SEARCH_DATA_FROM_ISMAP_URLS
  2955.       {
  2956.         char *punc;
  2957.         punc = XP_STRCHR(url_struct->address, '?');
  2958.         if(punc)
  2959.             *punc = '\0';  /* terminate here */
  2960.         punc = XP_STRCHR(url_struct->address, '#');
  2961.         if(punc)
  2962.             *punc = '\0';  /* terminate here */
  2963.       }
  2964. #endif /* STRIP_SEARCH_DATA_FROM_ISMAP_URLS */
  2965.  
  2966.         StrAllocCat(url_struct->address, buffer);
  2967.       }
  2968.  
  2969.     return(1); /* success */
  2970. }
  2971.  
  2972. /* FREE_AND_CLEAR will free a pointer if it is non-zero and
  2973.  * then set it to zero
  2974.  */
  2975. MODULE_PRIVATE void 
  2976. NET_f_a_c (char **pointer)
  2977. {
  2978.     if(*pointer) {
  2979.     XP_FREE(*pointer);
  2980.         *pointer = 0;
  2981.     }
  2982. }
  2983.  
  2984. /* recognizes URLs and their types.  Returns 0 (zero) if
  2985.  * it is unrecognized.
  2986.  */
  2987. PUBLIC int 
  2988. NET_URL_Type (CONST char *URL)
  2989. {
  2990.     /* Protect from SEGV */
  2991.     if (!URL || (URL && *URL == '\0'))
  2992.         return(0);
  2993.  
  2994.     switch(*URL) {
  2995.     case 'a':
  2996.     case 'A':
  2997.         if(!strncasecomp(URL,"about:security", 14))
  2998.             return(SECURITY_TYPE_URL);
  2999.         else if(!strncasecomp(URL,"about:",6))
  3000.             return(ABOUT_TYPE_URL);
  3001.         else if(!strncasecomp(URL,"addbook:",8))
  3002.             return(ADDRESS_BOOK_TYPE_URL);
  3003.         else if (!strncasecomp(URL, "addbook-ldap", 12)) /*no colon includes addbook-ldaps:*/
  3004.             return(ADDRESS_BOOK_LDAP_TYPE_URL);
  3005.         break;
  3006.  
  3007.     case 'd':
  3008.     case 'D':
  3009.         if(!strncasecomp(URL,"data:",5))
  3010.             return(DATA_TYPE_URL);
  3011.         break;
  3012.  
  3013.     case 'c':
  3014.     case 'C':
  3015.         if(!strncasecomp(URL,"castanet:",9))
  3016.             return(0);
  3017.         break;
  3018.  
  3019.     case 'f':
  3020.     case 'F':
  3021.         if(!strncasecomp(URL,"ftp:",4))
  3022.             return(FTP_TYPE_URL);
  3023.         else if(!strncasecomp(URL,"file:",5))
  3024.             return(FILE_TYPE_URL);
  3025.         break;
  3026.     case 'g':
  3027.     case 'G':
  3028.         if(!strncasecomp(URL,"gopher:",7)) 
  3029.             return(GOPHER_TYPE_URL);
  3030.         break;
  3031.     case 'h':
  3032.     case 'H':
  3033.         if(!strncasecomp(URL,"http:",5))
  3034.             return(HTTP_TYPE_URL);
  3035.         else if(!strncasecomp(URL,"https:",6))
  3036.             return(SECURE_HTTP_TYPE_URL);
  3037.         break;
  3038.     case 'i':
  3039.     case 'I':
  3040.         if(!strncasecomp(URL,"internal-gopher-",16))
  3041.             return(INTERNAL_IMAGE_TYPE_URL);
  3042.         else if(!strncasecomp(URL,"internal-news-",14))
  3043.             return(INTERNAL_IMAGE_TYPE_URL);
  3044.         else if(!strncasecomp(URL,"internal-edit-",14))
  3045.             return(INTERNAL_IMAGE_TYPE_URL);
  3046.         else if(!strncasecomp(URL,"internal-attachment-",20))
  3047.             return(INTERNAL_IMAGE_TYPE_URL);
  3048.         else if(!strncasecomp(URL,"internal-sa-",12))
  3049.             return(INTERNAL_IMAGE_TYPE_URL);
  3050.         else if(!strncasecomp(URL,"internal-smime-",15))
  3051.             return(INTERNAL_IMAGE_TYPE_URL);
  3052.         else if(!strncasecomp(URL,"internal-dialog-handler",23))
  3053.             return(HTML_DIALOG_HANDLER_TYPE_URL);
  3054.         else if(!strncasecomp(URL,"internal-panel-handler",22))
  3055.             return(HTML_PANEL_HANDLER_TYPE_URL);
  3056.         else if(!strncasecomp(URL,"internal-security-",18))
  3057.             return(INTERNAL_SECLIB_TYPE_URL);
  3058.         else if(!strncasecomp(URL,"internal-certldap",17))
  3059.             return(INTERNAL_CERTLDAP_TYPE_URL);
  3060.         else if(!strncasecomp(URL,"IMAP:",5))
  3061.             return(IMAP_TYPE_URL);
  3062.         break;
  3063.     case 'j':
  3064.     case 'J':
  3065.         if(!strncasecomp(URL, "javascript:",11))
  3066.             return(MOCHA_TYPE_URL);
  3067.         break;
  3068.     case 'l':
  3069.     case 'L':
  3070.         if(!strncasecomp(URL, "livescript:",11))
  3071.             return(MOCHA_TYPE_URL);
  3072.         else if (!strncasecomp(URL, "ldap:",5))
  3073.             return(LDAP_TYPE_URL);
  3074.         else if (!strncasecomp(URL, "ldaps:",6))
  3075.             return(SECURE_LDAP_TYPE_URL);
  3076.         break;
  3077.     case 'm':
  3078.     case 'M':
  3079.         if(!strncasecomp(URL,"mailto:",7)) 
  3080.             return(MAILTO_TYPE_URL);
  3081.         else if(!strncasecomp(URL,"mailbox:",8))
  3082.             return(MAILBOX_TYPE_URL);
  3083.         else if(!strncasecomp(URL, "mocha:",6))
  3084.             return(MOCHA_TYPE_URL);
  3085.         break;
  3086.     case 'n':
  3087.     case 'N':
  3088.         if(!strncasecomp(URL,"news:",5))
  3089.             return(NEWS_TYPE_URL);
  3090.         else if(!strncasecomp(URL,"nfs:",4))
  3091.             return(NFS_TYPE_URL);
  3092.         else if(!strncasecomp(URL, NETHELP_URL_PREFIX, sizeof(NETHELP_URL_PREFIX)-1))
  3093.             return(NETHELP_TYPE_URL);
  3094.         break;
  3095.     case 'p':
  3096.     case 'P':
  3097.         if(!strncasecomp(URL,"pop3:",5))
  3098.             return(POP3_TYPE_URL);
  3099.         break;
  3100.     case 'r':
  3101.     case 'R':
  3102.         if(!strncasecomp(URL,"rlogin:",7))
  3103.             return(RLOGIN_TYPE_URL);
  3104.         break;
  3105.     case 's':
  3106.     case 'S':
  3107.         if(!strncasecomp(URL,"snews:",6))
  3108.             return(NEWS_TYPE_URL);
  3109.         else if (!strncasecomp(URL,"search-libmsg:",14))
  3110.             return(MSG_SEARCH_TYPE_URL);
  3111.     case 't':
  3112.     case 'T':
  3113.         if(!strncasecomp(URL,"telnet:",7))
  3114.             return(TELNET_TYPE_URL);
  3115.         else if(!strncasecomp(URL,"tn3270:",7))
  3116.             return(TN3270_TYPE_URL);
  3117.         break;
  3118.     case 'u':
  3119.     case 'U':
  3120.         if(!strncasecomp(URL,"URN:",4))
  3121.             return(URN_TYPE_URL);
  3122.         break;
  3123.     case 'v':
  3124.     case 'V':
  3125.         if(!strncasecomp(URL, VIEW_SOURCE_URL_PREFIX, 
  3126.                               sizeof(VIEW_SOURCE_URL_PREFIX)-1))
  3127.             return(VIEW_SOURCE_TYPE_URL);
  3128.         break;
  3129.     case 'w':
  3130.     case 'W':
  3131.         if(!strncasecomp(URL,"wais:",5))
  3132.             return(WAIS_TYPE_URL);
  3133.         if(!strncasecomp(URL,"wysiwyg:",8))
  3134.             return(WYSIWYG_TYPE_URL);
  3135.         break;
  3136.     }
  3137.  
  3138.     /* no type match :( */
  3139.     return(0);
  3140. }
  3141.  
  3142. PUBLIC void
  3143. NET_PlusToSpace(char *str)
  3144. {
  3145.     for (; *str != '\0'; str++)
  3146.         if (*str == '+')
  3147.             *str = ' ';
  3148. }
  3149.  
  3150.  
  3151. static int
  3152. net_buffer_output_fn ( const char *buf, int32 size, void *closure)
  3153. {
  3154.   BufferStruct *bs = (BufferStruct *) closure;
  3155.   /* if the size greater or equal to the available buffer size
  3156.    * reallocate the buffer
  3157.    */
  3158.   XP_ASSERT (buf && bs && size > 0);
  3159.   if ( !buf || !bs || size <= 0 )
  3160.     return -1;
  3161.  
  3162.   if (size >= bs->size - bs->pos)
  3163.     {
  3164.       int32 len;
  3165.       char *newBuffer;
  3166.       
  3167.       len = (bs->size << 1) - bs->pos + size + 1; /* null terminated */
  3168.       if (bs->buffer)
  3169.         newBuffer = XP_REALLOC (bs->buffer, len);
  3170.       else
  3171.         newBuffer = XP_ALLOC(len);
  3172.       if (!newBuffer)
  3173.         return MK_OUT_OF_MEMORY;
  3174.       XP_MEMSET(newBuffer+bs->pos, 0, len-bs->pos);
  3175.       bs->size = len;
  3176.       bs->buffer = newBuffer;
  3177.     }
  3178.   XP_MEMCPY (bs->buffer+bs->pos, buf, size);
  3179.   bs->pos += size;
  3180.   return 0;
  3181. }
  3182.  
  3183. PRIVATE int32
  3184. net_URNProtoLoad(ActiveEntry *ce)
  3185. {
  3186.     char buffer[256];
  3187.  
  3188.     XP_STRCPY(buffer, XP_GetString(XP_ALERT_URN_USEHTTP));
  3189.     XP_STRNCAT(buffer, ce->URL_s->address, 150);
  3190.     buffer[255] = '\0'; /* in case strncat doesn't add one */
  3191.     FE_Alert(ce->window_id, buffer);
  3192.  
  3193.     return -1;
  3194. }
  3195.  
  3196. PRIVATE int32
  3197. net_URNProtoStub(ActiveEntry *ce)
  3198. {
  3199.     XP_ASSERT(0);
  3200.     return -1;
  3201. }
  3202.  
  3203. PRIVATE void
  3204. net_URNProtoCleanupStub(void)
  3205. {
  3206. }
  3207.  
  3208. /* a stub function for URN protocol converter.
  3209.  * right now we only proxy URN's
  3210.  * if URN's ever get worked on move this to another file
  3211.  */
  3212. PUBLIC void
  3213. NET_InitURNProtocol(void)
  3214. {
  3215.     static NET_ProtoImpl urn_proto_impl;
  3216.  
  3217.     urn_proto_impl.init = net_URNProtoLoad;
  3218.     urn_proto_impl.process = net_URNProtoStub;
  3219.     urn_proto_impl.interrupt = net_URNProtoStub;
  3220.     urn_proto_impl.cleanup = net_URNProtoCleanupStub;
  3221.  
  3222.     NET_RegisterProtocolImplementation(&urn_proto_impl, URN_TYPE_URL);
  3223. }
  3224.  
  3225. PRIVATE int32
  3226. net_NFSProtoLoad(ActiveEntry *ce)
  3227. {
  3228.         char buffer[256];
  3229.  
  3230.         XP_STRCPY(buffer, XP_GetString(XP_ALERT_NFS_USEHTTP));
  3231.         XP_STRNCAT(buffer, ce->URL_s->address, 150);
  3232.         buffer[255] = '\0'; /* in case strncat doesn't add one */
  3233.         FE_Alert(ce->window_id, buffer);
  3234.  
  3235.         return -1;
  3236. }
  3237.  
  3238. PRIVATE int32
  3239. net_NFSProtoStub(ActiveEntry *ce)
  3240. {
  3241.     XP_ASSERT(0);
  3242.     return -1;
  3243. }
  3244.  
  3245. PRIVATE void
  3246. net_NFSProtoCleanupStub(void)
  3247. {
  3248. }
  3249.  
  3250. /* a stub function for NFS protocol converter.
  3251.  * right now we only proxy NFS's
  3252.  * if NFS's ever get worked on move this to another file
  3253.  */
  3254. PUBLIC void
  3255. NET_InitNFSProtocol(void)
  3256. {
  3257.     static NET_ProtoImpl nfs_proto_impl;
  3258.  
  3259.     nfs_proto_impl.init = net_NFSProtoLoad;
  3260.     nfs_proto_impl.process = net_NFSProtoStub;
  3261.     nfs_proto_impl.interrupt = net_NFSProtoStub;
  3262.     nfs_proto_impl.cleanup = net_NFSProtoCleanupStub;
  3263.  
  3264.     NET_RegisterProtocolImplementation(&nfs_proto_impl, NFS_TYPE_URL);
  3265. }
  3266.  
  3267. PRIVATE int32
  3268. net_WAISProtoLoad(ActiveEntry *ce)
  3269. {
  3270.     char * alert = NET_ExplainErrorDetails(MK_NO_WAIS_PROXY);
  3271.  
  3272.     FE_Alert(ce->window_id, alert);
  3273.     FREE(alert);
  3274.  
  3275.     return -1;
  3276. }
  3277.  
  3278. PRIVATE int32
  3279. net_WAISProtoStub(ActiveEntry *ce)
  3280. {
  3281.     XP_ASSERT(0);
  3282.     return -1;
  3283. }
  3284.  
  3285. PRIVATE void
  3286. net_WAISProtoCleanupStub(void)
  3287. {
  3288. }
  3289.  
  3290. /* a stub function for WAIS protocol converter.
  3291.  * right now we only proxy WAIS's
  3292.  * if WAIS's ever get worked on move this to another file
  3293.  */
  3294. PUBLIC void
  3295. NET_InitWAISProtocol(void)
  3296. {
  3297.     static NET_ProtoImpl wais_proto_impl;
  3298.  
  3299.     wais_proto_impl.init = net_WAISProtoLoad;
  3300.     wais_proto_impl.process = net_WAISProtoStub;
  3301.     wais_proto_impl.interrupt = net_WAISProtoStub;
  3302.     wais_proto_impl.cleanup = net_WAISProtoCleanupStub;
  3303.  
  3304.     NET_RegisterProtocolImplementation(&wais_proto_impl, WAIS_TYPE_URL);
  3305. }
  3306.  
  3307. #ifdef MOZ_MAIL_NEWS    
  3308. PUBLIC char *
  3309. NET_Base64Encode (char *src, int32 srclen)
  3310. {
  3311.   BufferStruct bs;
  3312.   MimeEncoderData *encoder_data = NULL;
  3313.  
  3314.   XP_ASSERT (src);
  3315.   if (!src)
  3316.     return NULL;
  3317.   else if (srclen == 0)
  3318.     return XP_STRDUP("");
  3319.  
  3320.   XP_MEMSET (&bs, 0, sizeof (BufferStruct));
  3321.   encoder_data = MimeB64EncoderInit(net_buffer_output_fn, (void *) &bs);
  3322.   if (!encoder_data)
  3323.     return NULL;
  3324.  
  3325.   if (MimeEncoderWrite(encoder_data, src, srclen) < 0)
  3326.     {
  3327.       MimeEncoderDestroy(encoder_data, FALSE);
  3328.       XP_FREEIF(bs.buffer);
  3329.       return NULL;
  3330.     }
  3331.   
  3332.   MimeEncoderDestroy(encoder_data, FALSE);
  3333.   /* caller must free the returned pointer to prevent
  3334.    * memory leak problem.
  3335.    */
  3336.   return bs.buffer;
  3337. }
  3338.  
  3339. PUBLIC char *
  3340. NET_Base64Decode (char *src, 
  3341.                   int32 srclen)
  3342. {
  3343.   BufferStruct bs;
  3344.   MimeDecoderData *decoder_data = NULL;
  3345.  
  3346.   XP_ASSERT (src);
  3347.   if (!src)
  3348.     return NULL;
  3349.   else if (srclen == 0)
  3350.     return XP_STRDUP("");
  3351.  
  3352.   XP_MEMSET (&bs, 0, sizeof (BufferStruct));
  3353.   decoder_data = MimeB64DecoderInit(net_buffer_output_fn, (void *) &bs);
  3354.   if (!decoder_data)
  3355.     return NULL;
  3356.  
  3357.   if (MimeDecoderWrite(decoder_data, src, srclen) < 0)
  3358.     {
  3359.       MimeDecoderDestroy(decoder_data, FALSE);
  3360.       XP_FREEIF(bs.buffer);
  3361.       return NULL;
  3362.     }
  3363.   
  3364.   MimeDecoderDestroy(decoder_data, FALSE);
  3365.   /* caller must free the returned pointer to prevent
  3366.    * memory leak problem.
  3367.    */
  3368.   return bs.buffer;
  3369. }
  3370.  
  3371. #endif /* MOZ_MAIL_NEWS */
  3372.