home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libnet / mkformat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  29.5 KB  |  1,263 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.  * determine the format of a file
  20.  *
  21.  * Started with Rob's code and
  22.  * then hacked up by Lou.
  23.  */
  24.  
  25. #include "mkutils.h"
  26. #include "mkformat.h"
  27.  
  28. static char *net_default_types [] = {
  29. # include "mktypes.h"
  30.   0 };
  31.  
  32.  
  33. /* func proto
  34.  */
  35. PRIVATE int cinfo_parse_mcc_line(char *line, Bool is_external,
  36.                     Bool is_local, char **src_string);
  37. PRIVATE int net_cinfo_merge(char *fn, Bool is_local);
  38.  
  39. /* ----------------------------- Static data ------------------------------ */
  40.  
  41. /* The master database of content info (linked list) */
  42. PRIVATE XP_List * NET_ciMasterList=0;
  43.  
  44. /*
  45.  * cinfo.c: Content Information for a file, i.e. its type, etc.
  46.  *
  47.  * See cinfo.h for full details.
  48.  *
  49.  * Rob McCool
  50.  */
  51.  
  52. /* init types loads standard types so that a config file
  53.  * is not required and can also read
  54.  * a mime types file if filename is passed in non empty and
  55.  * non null
  56.  *
  57.  * on each call to NET_InitFileFormatTypes the extension list
  58.  * will be completely free'd and rebuilt.
  59.  *
  60.  * if you pass in NULL filename pointers they will not be
  61.  * attempted to be read
  62.  */
  63. PUBLIC int
  64. NET_InitFileFormatTypes(char * personal_file, char *global_file)
  65. {
  66.   /* init the data structures
  67.    */
  68.   int i = 0;
  69.  
  70. #ifdef XP_UNIX
  71.   NET_CleanupFileFormat(NULL);
  72. #else /* !XP_UNIX */
  73.   NET_CleanupFileFormat();
  74. #endif /* !XP_UNIX */
  75.   NET_ciMasterList = XP_ListNew();
  76.  
  77.   TRACEMSG((" Setting up File Format code"));
  78.  
  79.   while (net_default_types [i])
  80.     {
  81.       char buf [256];
  82.       char *src_string = 0;
  83.       XP_STRCPY (buf, net_default_types [i]);
  84.       StrAllocCopy(src_string, buf);
  85.       cinfo_parse_mcc_line (buf, FALSE, FALSE, &src_string); /* destroys buf */
  86.       i++;
  87.       if (src_string) XP_FREE(src_string);
  88.       
  89.     }
  90.  
  91.   /* read the external mime types file and return */
  92.   if(global_file)
  93.     {
  94.       net_cinfo_merge(global_file, FALSE);
  95.     }
  96.   if(personal_file)
  97.     {
  98.       net_cinfo_merge(personal_file, TRUE);
  99.     }
  100.  
  101.   return(0);
  102. }
  103.  
  104. /* -------------------------- Module structures --------------------------- */
  105.  
  106.  
  107.  
  108. static NET_cinfo default_cinfo_type = {
  109. #ifdef MCC_PROXY
  110.     MAGNUS_INTERNAL_UNKNOWN,
  111. #else
  112.     UNKNOWN_CONTENT_TYPE,
  113. #endif
  114.     0,
  115.     0,
  116.     0,
  117.     0,
  118.     0,
  119.     TRUE,
  120.     0
  121. };
  122.  
  123. #ifdef NOT_USED
  124. static NET_cinfo default_cinfo_enc = {
  125.     0,
  126.     0,
  127.     0,
  128.     0,
  129.     0,
  130.     0,
  131.     1,
  132.     0
  133. };
  134. #endif /* NOT_USED */
  135.  
  136. /* ------------------------------ _cinfo_free ------------------------------ */
  137.  
  138.  
  139. PRIVATE void
  140. _cinfo_free(NET_cinfo *ci)
  141. {
  142.  
  143.     FREEIF(ci->type);
  144.     FREEIF(ci->encoding);
  145.     FREEIF(ci->language);
  146.     FREEIF(ci->desc);
  147.     FREEIF(ci->icon);
  148.     FREEIF(ci->alt_text);
  149. }
  150.  
  151.  
  152. /* ---------------------------- NET_cdataCreate ---------------------------- */
  153.  
  154.  
  155. PUBLIC NET_cdataStruct *
  156. NET_cdataCreate(void)
  157. {
  158.   NET_cdataStruct *cd = XP_NEW(NET_cdataStruct);
  159.  
  160.   if(!cd)
  161.     return(NULL);
  162.  
  163.   memset(cd, 0, sizeof(NET_cdataStruct));
  164.  
  165.   return cd;
  166. }
  167.  
  168.  
  169. /* ----------------------------- NET_cdataFree ---------------------------- */
  170.  
  171.  
  172. PUBLIC void
  173. NET_cdataFree(NET_cdataStruct *cd)
  174. {
  175.   register int x;
  176.  
  177.   if(cd->exts)
  178.     {
  179.       for(x = 0; x < cd->num_exts; x++)
  180.         XP_FREE(cd->exts[x]);
  181.       XP_FREE(cd->exts);
  182.     }
  183.   if ( cd->src_string )
  184.     XP_FREE(cd->src_string);
  185.  
  186.   _cinfo_free(&cd->ci);
  187.  
  188.   XP_FREE(cd);
  189.   cd = 0;
  190. }
  191.  
  192. /* ---------------------------- NET_cdataAdd ------------------------------- */
  193.  
  194. PUBLIC void
  195. NET_cdataAdd(NET_cdataStruct *cd)
  196. {
  197.     XP_ListAddObject(NET_ciMasterList, cd);
  198. }
  199.  
  200. /* ---------------------------- NET_cdataRemove ---------------------------- */
  201.  
  202. PUBLIC void
  203. NET_cdataRemove(NET_cdataStruct *cd)
  204. {
  205.   XP_ListRemoveObject(NET_ciMasterList, cd);
  206.  
  207.   NET_cdataFree(cd);
  208. }
  209.  
  210. PUBLIC NET_cdataStruct*
  211. NET_cdataExist(NET_cdataStruct *old_cd )
  212. {
  213.   NET_cdataStruct *found_cd = NULL;
  214.   NET_cdataStruct *cd = NULL;
  215.   XP_List *infoList;
  216.  
  217.   infoList = cinfo_MasterListPointer();
  218.  
  219.   if ( !infoList )
  220.     return found_cd;
  221.  
  222.   while ((cd= (NET_cdataStruct *)XP_ListNextObject(infoList)) != NULL)
  223.     {
  224.       if ( old_cd->ci.type &&
  225.            cd->ci.type &&
  226.            !strcasecomp(old_cd->ci.type, cd->ci.type))
  227.         {
  228.           /* found matching type */
  229.           found_cd = cd;
  230.           break;
  231.         }
  232.       else if ( !old_cd->ci.type &&
  233.                 old_cd->ci.encoding &&
  234.                 cd->ci.encoding &&
  235.                 !strcasecomp(old_cd->ci.encoding, cd->ci.encoding))
  236.         {
  237.           /* found matching encoding */
  238.           found_cd = cd;
  239.           break;
  240.         }
  241.     }
  242.   return found_cd;
  243. }
  244.  
  245. #if 0
  246. PRIVATE
  247. Bool
  248. net_cdata_exist_ext( char *ext, NET_cdataStruct *cd )
  249. {
  250.   Bool not_found = FALSE;
  251.   int n;
  252.  
  253.   if (!cd->exts) return not_found;
  254.  
  255.   for ( n = 0; n < cd->num_exts; n++ )
  256.     {
  257.       if (!strcasecomp(cd->exts[n], ext) )
  258.         {
  259.           not_found = TRUE;
  260.           break;
  261.         }
  262.     }
  263.   return not_found;
  264. }
  265. #endif
  266.  
  267. /* ---------------------------- net_cdata_new_ext ----------------------------- */
  268.  
  269.  
  270. PRIVATE
  271. void
  272. net_cdata_new_ext(char *ext, NET_cdataStruct *cd)
  273. {
  274.   int n = cd->num_exts;
  275.  
  276.   cd->exts = (char **) (n ? XP_REALLOC(cd->exts, (n+1)*sizeof(char *))
  277.                         : XP_ALLOC(sizeof(char *)));
  278.  
  279.   if(!cd->exts)
  280.     return;
  281.  
  282.   cd->exts[n] = 0;
  283.   StrAllocCopy(cd->exts[n], ext);
  284.   cd->num_exts = ++n;
  285. }
  286.  
  287.  
  288. /* ----------------------------- cinfo_merge ------------------------------ */
  289.  
  290.  
  291. int _cinfo_parse_mimetypes(XP_File fp, char *t, Bool is_local);
  292. int _cinfo_parse_mcc(XP_File fp, char *t, Bool is_local);
  293.  
  294. PRIVATE int
  295. net_cinfo_merge(char *fn, Bool is_local)
  296. {
  297.   XP_File fp;
  298.   char t[CINFO_MAX_LEN];
  299.   int ret;
  300.  
  301.   TRACEMSG(("\n\nnet_cinfo_merge: called with %s\n\n\n", fn));
  302.   if(!(fp = XP_FileOpen(fn ? fn : "mime.types", xpMimeTypes, XP_FILE_READ))) {
  303.     TRACEMSG(("cinfo.c: File open failed"));
  304.     return -1;
  305.   }
  306.  
  307.   TRACEMSG(("Reading mime.types file"));
  308.  
  309.   if(!(XP_FileReadLine(t, CINFO_MAX_LEN, fp))) {
  310.     TRACEMSG(("cinfo.c: Mime types file is empty"));
  311.     return -1;
  312.  
  313.   } else if(!strncmp(t, MCC_MT_MAGIC, MCC_MT_MAGIC_LEN) ||
  314.             !strncmp(t, NCC_MT_MAGIC, NCC_MT_MAGIC_LEN)) {
  315.     /* Look for magic number */
  316.     TRACEMSG(("Loading MCC mime types file"));
  317.     ret = _cinfo_parse_mcc(fp, t, is_local);
  318.  
  319.   } else {
  320.     TRACEMSG(("Loading old NCSA mime types file"));
  321.     ret = _cinfo_parse_mimetypes(fp, t, is_local);
  322.   }
  323.  
  324.   XP_FileClose(fp);
  325.   return ret;
  326. }
  327.  
  328.  
  329. static NET_cinfo *
  330. net_cinfo_find_type_or_encoding (char *uri, XP_Bool type_p)
  331. {
  332.   char *start = uri;
  333.   char *end, *c;
  334.   NET_cinfo *result = &default_cinfo_type;
  335.   XP_Bool saw_encoding = FALSE;
  336.  
  337.   c = XP_STRRCHR (uri, '/');
  338.   if (c) start = c;
  339.  
  340.   end = start + XP_STRLEN (start);
  341.   c = XP_STRRCHR (start, '?');
  342.   if (c) end = c;
  343.   c = XP_STRRCHR (start, '#');
  344.   if (c && c < end) end = c;
  345.  
  346. AGAIN:
  347.   for (c = end - 1; c >= uri; c--)
  348.     if (*c == '/' || *c == '.')
  349.       break;
  350.  
  351.   if (c >= uri && *c == '.')
  352.     {
  353.       int32 i;
  354.       XP_List *list_ptr = NET_ciMasterList;
  355.       NET_cdataStruct *cdata;
  356.       uint32 ext_len;
  357.       start = c + 1;
  358.       ext_len = end - start;
  359.       while ((cdata = (NET_cdataStruct *) XP_ListNextObject (list_ptr)) != NULL)
  360.         for (i = cdata->num_exts - 1; i >= 0; i--)
  361.           if (XP_STRLEN (cdata->exts[i]) == ext_len &&
  362.               !strncasecomp (start, cdata->exts [i], ext_len))
  363.             {
  364.               if (type_p && cdata->ci.type)
  365.                 {
  366.                   /* We are looking for a type, and this extension represents
  367.                      one.  Since this is the last one in the path (since we
  368.                      start from the end and go backwards) we're done now.
  369.                    */
  370.                   return &cdata->ci;
  371.                 }
  372.               else if (type_p && cdata->ci.encoding)
  373.                 {
  374.                   /* We are looking for a type, and this extension represents
  375.                      an encoding.  Skip over it and look for the next
  376.                      extension earlier in the file name (as that may turn out
  377.                      to be a type which we should take instead.)
  378.  
  379.                      But, if this is the second encoding we've seen, then the
  380.                      final content-type is irrelevant, because we have no
  381.                      mechanism for decoding multiple encodings.  So, while
  382.                      "foo.gif.gz" gets type gif, encoding gz, "foo.tar.gz.uu"
  383.                      gets type unknown, encoding uu.  This is especially
  384.                      important for the types that we put on outgoing MIME
  385.                      attachments.
  386.                    */
  387.                   if (saw_encoding)
  388.                     return &default_cinfo_type;
  389.                   saw_encoding = TRUE;
  390.                   end = start - 1;
  391.                   goto AGAIN;
  392.                 }
  393.               else if (cdata->ci.type)
  394.                 {
  395.                   XP_ASSERT (!type_p);
  396.                   /* We are looking for an encoding, and this extension
  397.                      represents a content-type.  That means that there are
  398.                      no encodings after the type in this file name, and
  399.                      therefore it has no encoding (an encoding which occurs
  400.                      before a type doesn't count: "foo.uu.gif" should be of
  401.                      type gif with no encoding, not encoding uu. Also,
  402.                      "foo.uu.unknown" should be of an unknown type with no
  403.                      encoding; and "foo.uu.gif.Z" should be type gif,
  404.                      encoding compress.)
  405.                    */
  406.                   return &default_cinfo_type;
  407.                 }
  408.               else if (cdata->ci.encoding)
  409.                 {
  410.                   XP_ASSERT (!type_p);
  411.                   /* We are looking for an encoding, and this extension
  412.                      represents one.  It is the last one in the file name,
  413.                      so now we're done.  ("foo.gz.uu" gets encoding "uu"
  414.                      instead of "gz".)
  415.                    */
  416.                   return &cdata->ci;
  417.                 }
  418.               /* Else, this cdata is junk, or something...  Skip it. */
  419.             }
  420.     }
  421.  
  422.   return (result);
  423. }
  424.  
  425.  
  426. PUBLIC NET_cinfo *
  427. NET_cinfo_find_type (char *uri)
  428. {
  429.   return net_cinfo_find_type_or_encoding (uri, TRUE);
  430. }
  431.  
  432. PUBLIC NET_cinfo *
  433. NET_cinfo_find_enc (char *uri)
  434. {
  435.   return net_cinfo_find_type_or_encoding (uri, FALSE);
  436. }
  437.  
  438.  
  439. #if defined(DEBUG) && defined(XP_UNIX)
  440. void
  441. print_mime_types()
  442. {
  443.   int32 i;
  444.   XP_List *list_ptr = NET_ciMasterList;
  445.   NET_cdataStruct *cdata;
  446.  
  447.   fprintf(stderr, "\n---------\n");
  448.  
  449.   while ((cdata = (NET_cdataStruct *) XP_ListNextObject (list_ptr)))
  450.     {
  451.       fprintf (stderr, "%s%s%s (%s; %s):",
  452.                (cdata->ci.type ? cdata->ci.type : ""),
  453.                (cdata->ci.type && *cdata->ci.type &&
  454.                 cdata->ci.encoding && *cdata->ci.encoding
  455.                 ? "+" : ""),
  456.                (cdata->ci.encoding ? cdata->ci.encoding : ""),
  457.                (cdata->ci.desc ? cdata->ci.desc : "no desc"),
  458.                (cdata->ci.icon ? cdata->ci.icon : "no icon"));
  459.  
  460.       for (i = cdata->num_exts - 1; i >= 0; i--)
  461.         fprintf (stderr, " %s", cdata->exts[i]);
  462.       fprintf (stderr, "\n");
  463.     }
  464. }
  465. #endif /* DEBUG && XP_UNIX */
  466.  
  467.  
  468. /* return a cdataStruct from a mime_type
  469.  */
  470. PRIVATE NET_cdataStruct *
  471. NET_cinfo_find_cdata_by_type(char *mime_type)
  472. {
  473.   NET_cdataStruct *cdata;
  474.   XP_List * list_ptr;
  475.  
  476.   if(!mime_type)
  477.     return(NULL);
  478.  
  479.   list_ptr = NET_ciMasterList;
  480.   while((cdata = (NET_cdataStruct *) XP_ListNextObject(list_ptr)) != NULL)
  481.     {
  482.       if(cdata->ci.type && !strcasecomp(mime_type, cdata->ci.type))
  483.         return(cdata);
  484.     }
  485.  
  486.   return(NULL);
  487. }
  488.  
  489. /* return a cinfo from a mime_type
  490.  */
  491. PUBLIC NET_cinfo *
  492. NET_cinfo_find_info_by_type(char *mime_type)
  493. {
  494.   NET_cdataStruct *cdata = NET_cinfo_find_cdata_by_type(mime_type);
  495.  
  496.   if(cdata)
  497.     return(&cdata->ci);
  498.   else
  499.     return(NULL);
  500. }
  501.  
  502.  
  503. /* --------------------------- cinfo_find_ext ------------------------------ */
  504.  
  505. /* returns an extension (without the ".") for
  506.  * a given mime type.
  507.  *
  508.  * If no match is found NULL is returned.
  509.  *
  510.  * Do not free the returned char *
  511.  */
  512. PUBLIC char *
  513. NET_cinfo_find_ext(char *mime_type)
  514. {
  515.   NET_cdataStruct *cdata = NET_cinfo_find_cdata_by_type(mime_type);
  516.  
  517.   if(cdata)
  518.     return(cdata->exts[0]);
  519.   else
  520.     return(NULL);
  521. }
  522.  
  523.  
  524. /* ----------------------------- File parsers ----------------------------- */
  525.  
  526.  
  527. #if 0
  528. static void
  529. net_build_string(char** curr_str, char *new_str)
  530. {
  531.   int len;
  532.  
  533.   if ( new_str && *new_str )
  534.     {
  535.       if (!*curr_str )
  536.         {
  537.           len = strlen(new_str);
  538.           *curr_str = (char *)XP_ALLOC((len+1)*sizeof(char));
  539.           sprintf(*curr_str, "%s", new_str);
  540.         }
  541.       else
  542.         {
  543.           len = strlen(new_str) + strlen(*curr_str);
  544.           *curr_str = (char *)XP_ALLOC((len+1)*sizeof(char));
  545.           sprintf(*curr_str, "%s%s", *curr_str, new_str);
  546.         }
  547.     }
  548. }
  549. #endif /* 0 */
  550.  
  551. /* Parse old NCSA mime.types files */
  552.  
  553. int
  554. _cinfo_parse_mimetypes(XP_File fp, char *t, Bool is_local)
  555. {
  556.   char *ext, *end;
  557.   NET_cdataStruct *cd;
  558.   char *src_string = 0;
  559.  
  560.   /* t is already filled. */
  561.   while(1) {
  562.  
  563.     if ( src_string )
  564.       {
  565.         src_string = XP_AppendStr(src_string, t);
  566.       }
  567.     else
  568.       {
  569.         StrAllocCopy(src_string, t);
  570.       }
  571.  
  572.     while((*t) && (XP_IS_SPACE(*t)))
  573.       ++t;
  574.  
  575.     if(*t && (*t != '#')) {
  576.       ext = t;
  577.       while((*ext) && (!XP_IS_SPACE(*ext))) ++ext;
  578.       if((*ext))
  579.         *ext++ = '\0';
  580.  
  581.       cd = NULL;
  582.  
  583.       while((*ext)) {
  584.         while((*ext) && (XP_IS_SPACE(*ext))) ++ext;
  585.  
  586.         if((*ext)) {
  587.           if(!cd) {
  588.             cd = NET_cdataCreate();
  589.             if(!cd)
  590.               return(-1);
  591.           }
  592.  
  593.           cd->is_local = is_local;
  594.           cd->is_external = FALSE; /* don't count these as external types */
  595.  
  596.           cd->is_modified = FALSE; /* default is not modified in any way */
  597.           end = ext+1;
  598.           while((*end) && (!XP_IS_SPACE(*end))) ++end;
  599.           if(*end)
  600.             *end++ = '\0';
  601.           net_cdata_new_ext(ext, cd);
  602.           ext = end;
  603.         }
  604.       }
  605.       if(cd) {
  606.         NET_cdataStruct *old_cd = NULL;
  607.         FREEIF(cd->ci.type);
  608.         cd->ci.type = 0;
  609.         StrAllocCopy(cd->ci.type, t);
  610.         FREEIF(cd->src_string);
  611.         StrAllocCopy(cd->src_string, src_string);
  612.  
  613.         if ( (old_cd =  NET_cdataExist(cd)) != NULL)
  614.           /* Found an old one, remove it first */
  615.           {
  616.             /* Extra hack: if the old one defined an icon, or a desc,
  617.                and the new one does not, carry those over. */
  618.             char *icon = (old_cd->ci.icon && !cd->ci.icon
  619.                           ? XP_STRDUP(old_cd->ci.icon)
  620.                           : 0);
  621.             char *desc = (old_cd->ci.desc && !cd->ci.desc
  622.                           ? XP_STRDUP(old_cd->ci.desc)
  623.                           : 0);
  624.  
  625.             NET_cdataRemove(old_cd);
  626.             old_cd = 0;
  627.  
  628.             if (icon) cd->ci.icon = icon;
  629.             if (desc) cd->ci.desc = desc;
  630.           }
  631.         /* Not an existing type, we add a new one */
  632.         NET_cdataAdd(cd);
  633.         XP_FREE(src_string);
  634.         src_string = 0;
  635.       }
  636.     }
  637.     if(!(XP_FileReadLine(t, CINFO_MAX_LEN, fp)))
  638.       break;
  639.   }
  640.   return 0;
  641. }
  642.  
  643.  
  644. PUBLIC int
  645. cinfo_parse_mcc_line(char *line, Bool is_external, Bool is_local,
  646.                      char **src_string)
  647. {
  648.   int ln = 1;
  649.   char *t, *u, *v, *name, *value, c;
  650.   NET_cdataStruct *cd;
  651.  
  652.   if(line && *line)
  653.     {
  654.       cd = NULL;
  655.  
  656.       t = line;
  657.  
  658.       if((*t) && (*t != '#')) {
  659.         while(1) {
  660.  
  661.           while(*t && XP_IS_SPACE(*t)) ++t;
  662.           if(!(*t))
  663.             break;
  664.           name = t;
  665.  
  666.           while(*t && (*t != '=')) ++t;
  667.           if(!(*t)) {
  668.             TRACEMSG(("line %d: name without =", ln));
  669.             if(cd)
  670.               NET_cdataFree(cd);
  671.             return (-1);
  672.           }
  673.           for(u = t - 1; XP_IS_SPACE(*u); --u)
  674.             ;
  675.           *(u+1) = '\0';   /* terminate name */
  676.           ++t;
  677.           while(*t && (*t != '\"') && (XP_IS_SPACE(*t))) ++t;
  678.           if(!(*t)) {
  679.             TRACEMSG(("line %d: empty value", ln));
  680.             if(cd)
  681.               NET_cdataFree(cd);
  682.             return (-1);
  683.           }
  684.           if(*t == '\"') {
  685.             value = ++t;
  686.             while(*t && (*t != '\"')) ++t;
  687.             if(!(*t)) {
  688.               TRACEMSG(("line %d: missing closing quotes", ln));
  689.               if(cd)
  690.                 NET_cdataFree(cd);
  691.               return (-1);
  692.             }
  693.           }
  694.           else {
  695.             value = t;
  696.             while(*t && (!XP_IS_SPACE(*t))) ++t;
  697.             /* null t is okay */
  698.           }
  699.           if(*t) *t++ = '\0';
  700.           if(!cd) {
  701.             cd = NET_cdataCreate();
  702.             if(!cd)
  703.               return(0);
  704.  
  705.             cd->is_external = is_external;
  706.             cd->is_modified = FALSE; /* default is "not modified yet!*/
  707.             cd->is_local = is_local;
  708.             FREEIF(cd->src_string);
  709.             cd->src_string = *src_string;
  710.             *src_string = 0;
  711.           }
  712.  
  713.           if(!strcasecomp(name, "type")) {
  714.             FREEIF(cd->ci.type);
  715.             cd->ci.type = 0;
  716.             StrAllocCopy(cd->ci.type, value);
  717.  
  718.           } else if(!strcasecomp(name, "enc")) {
  719.             FREEIF(cd->ci.encoding);
  720.             cd->ci.encoding = 0;
  721.             StrAllocCopy(cd->ci.encoding, value);
  722.  
  723.           } else if(!strcasecomp(name, "lang")) {
  724.             FREEIF(cd->ci.language);
  725.             cd->ci.language = 0;
  726.             StrAllocCopy(cd->ci.language, value);
  727.  
  728.           } else if(!strcasecomp(name, "desc")) {
  729.             FREEIF(cd->ci.desc);
  730.             cd->ci.desc = 0;
  731.             StrAllocCopy(cd->ci.desc, value);
  732.  
  733.           } else if(!strcasecomp(name, "alt")) {
  734.             FREEIF(cd->ci.alt_text);
  735.             cd->ci.alt_text = 0;
  736.             StrAllocCopy(cd->ci.alt_text, value);
  737.  
  738.           } else if(!strcasecomp(name, "icon")) {
  739.             FREEIF(cd->ci.icon);
  740.             cd->ci.icon = 0;
  741.             StrAllocCopy(cd->ci.icon, value);
  742.  
  743.           } else if(!strcasecomp(name, "exts")) {
  744.             u = value;
  745.             while(1) {
  746.               v = u;
  747.               while(*u && (*u != ',')) ++u;
  748.               c = *u;
  749.               *u = '\0';
  750.               net_cdata_new_ext(v, cd);
  751.               if(c)
  752.                 ++u;
  753.               else
  754.                 break;
  755.             }
  756.           }
  757.         }
  758.  
  759.         /* Some people like to be clever and use mime.types entries
  760.            like "type=application/x-tar  enc=x-gzip  exts=tgz",
  761.            but unfortunately, that doesn't even come close to working,
  762.            and will override (delete) the existing tar entry, causing
  763.            disaster of various forms.
  764.  
  765.            So, if this line defines *both* "type" and "enc", just throw
  766.            it away.
  767.          */
  768.         if (cd &&
  769.             cd->ci.type && *cd->ci.type &&
  770.             cd->ci.encoding && *cd->ci.encoding)
  771.           {
  772.             NET_cdataFree(cd);
  773.             cd = 0;
  774.           }
  775.  
  776.         if(cd)
  777.           {
  778.             NET_cdataStruct    *old_cd = NULL;
  779.  
  780.             if ((old_cd =  NET_cdataExist(cd)) != NULL)
  781.               /* Found an old one, remove it first */
  782.               {
  783.                 /* Extra hack: if the old one defined an icon, or a desc,
  784.                    and the new one does not, carry those over. */
  785.                 char *icon = (old_cd->ci.icon && !cd->ci.icon
  786.                               ? XP_STRDUP(old_cd->ci.icon)
  787.                               : 0);
  788.                 char *desc = (old_cd->ci.desc && !cd->ci.desc
  789.                               ? XP_STRDUP(old_cd->ci.desc)
  790.                               : 0);
  791.  
  792.                 NET_cdataRemove(old_cd);
  793.                 old_cd = 0;
  794.  
  795.                 if (icon) cd->ci.icon = icon;
  796.                 if (desc) cd->ci.desc = desc;
  797.               }
  798.             NET_cdataAdd(cd);
  799.           }
  800.       }
  801.  
  802.       ln++;
  803.     }
  804.   return 0; /* #### what should return value be? */
  805. }
  806.  
  807.  
  808. /* Parse sexy new MCC mime types files */
  809. int
  810. _cinfo_parse_mcc(XP_File fp, char *line, Bool is_local)
  811. {
  812.   char *end;
  813.   char *src_string = 0;
  814.  
  815.   TRACEMSG(("mime.types file is MCC type"));
  816.  
  817.   /* t is already filled. */
  818.  
  819.   if ( !src_string )
  820.     StrAllocCopy(src_string, line);
  821.   else
  822.     {
  823.       src_string = XP_AppendStr(src_string, line);
  824.     }
  825.   while(1) {
  826.     cinfo_parse_mcc_line(line, TRUE, is_local, &src_string);
  827.  
  828.     if(!(XP_FileReadLine(line, CINFO_MAX_LEN, fp)))
  829.       break;
  830.  
  831.     if ( !src_string )
  832.       StrAllocCopy(src_string, line);
  833.     else
  834.       {
  835.         src_string = XP_AppendStr(src_string, line);
  836.       }
  837.     /* assemble extended lines
  838.      */
  839.     end = &line[XP_STRLEN(line)-1];
  840.     while (end > line && (*end == CR || *end == LF))
  841.       end--;
  842.     while(*end == '\\')
  843.       {
  844.         *end = ' ';
  845.         end++;
  846.  
  847.         if(!(XP_FileReadLine(end, CINFO_MAX_LEN-(end-line), fp)))
  848.           break;
  849.  
  850.         if ( !src_string )
  851.           StrAllocCopy(src_string, end);
  852.         else
  853.           src_string = XP_AppendStr(src_string, end);
  854.  
  855.  
  856.         end = &end[XP_STRLEN(end)-1];
  857.         while (end > line && (*end == CR || *end == LF))
  858.           end--;
  859.  
  860.         if((end-line)+2 >= CINFO_MAX_LEN)
  861.           break;
  862.       }
  863.   }
  864.  
  865.   return 0;
  866. }
  867.  
  868. /* return the master cdata List pointer
  869.  */
  870. PUBLIC XP_List *
  871. cinfo_MasterListPointer()
  872. {
  873.   return(NET_ciMasterList);
  874. }
  875.  
  876. /* fills in cdata structure
  877.  *
  878.  * if cdata for a given type do not exist, create a new one
  879.  */
  880. PUBLIC void
  881. NET_cdataCommit(char * mimeType, char * cdataString)
  882. {
  883.   XP_List * extensionList;
  884.   NET_cdataStruct * matchInfo = NULL;
  885.   int listSize;
  886.   int i;
  887.  
  888.   extensionList = cinfo_MasterListPointer();
  889.   if (!extensionList)
  890.        {
  891.       NET_ciMasterList = XP_ListNew();
  892.       extensionList = cinfo_MasterListPointer();  /* Lou help me out here,
  893.                                                      create the list and
  894.                                                      matchInfo */
  895.     }
  896.   if (!extensionList)
  897.     return;
  898.  
  899.   listSize = XP_ListCount(extensionList);
  900.   for (i = 1; i<=listSize; i++)
  901.     {
  902.       NET_cdataStruct * cinfo =
  903.         (NET_cdataStruct *)XP_ListGetObjectNum(extensionList, i);
  904.       if (cinfo &&
  905.           cinfo->ci.type &&
  906.           (strcasecomp(mimeType, cinfo->ci.type) == 0))
  907.         {
  908.           int j;
  909.           matchInfo = cinfo;
  910.           for ( j= 0; j< matchInfo->num_exts; j++)  /* Free 'em all */
  911.             XP_FREE((char*)matchInfo->exts[j]);
  912.           XP_FREE(matchInfo->exts);
  913.           matchInfo->exts = NULL;
  914.           break;
  915.         }
  916.     }
  917.  
  918.   if (matchInfo == NULL)
  919.     {
  920.       matchInfo = NET_cdataCreate();
  921.       if (matchInfo == NULL)
  922.         {
  923.           return;
  924.         }
  925.       else
  926.         {
  927.           FREEIF(matchInfo->ci.type);
  928.           matchInfo->ci.type = 0;
  929.           StrAllocCopy(matchInfo->ci.type, mimeType);
  930.         }
  931.       NET_cdataAdd(matchInfo);
  932.  
  933.     }
  934.   /* Found the right type */
  935.   {
  936.     char newExtension[30]; /* extension limit is 30 chars */
  937.     char * citer;
  938.     int newExIndex = 0;
  939.     XP_BZERO(newExtension, sizeof(newExtension));
  940.     citer = cdataString;
  941.     newExtension[0] = 0;
  942.     matchInfo->num_exts = 0;
  943.     matchInfo->exts = (char**)XP_ALLOC(10);
  944.     memset(newExtension, 0, 30);
  945.     if (matchInfo->exts == NULL)
  946.       return;
  947.     while (*citer != 0)    /* Parse the string. Skip all non-c*/
  948.       {
  949.         if (isalnum(*citer) && (newExIndex < 29)) /* XP_IS_ALPHA(*citer) */
  950.           newExtension[newExIndex++] = *citer;
  951.         else if (XP_STRLEN(newExtension) > 0)
  952.           {
  953.             char * newString = NULL;
  954.             newExtension[newExIndex] = 0;
  955.             StrAllocCopy(newString, newExtension);
  956.             matchInfo->num_exts++;
  957.             matchInfo->exts =
  958.               (char**)XP_REALLOC(matchInfo->exts,
  959.                                  matchInfo->num_exts * sizeof(void*));
  960.             matchInfo->exts[matchInfo->num_exts-1] = newString;
  961.             newExIndex = 0;
  962.             newExtension[0] = 0;
  963.           }
  964.         citer++;
  965.       }
  966.     /* commit the last extension, if there was one */
  967.     if (XP_STRLEN(newExtension) > 0)
  968.       {
  969.         char * newString = NULL;
  970.         newExtension[newExIndex] = 0;
  971.         StrAllocCopy(newString, newExtension);
  972.         matchInfo->num_exts++;
  973.         matchInfo->exts =
  974.           (char**)XP_REALLOC(matchInfo->exts,
  975.                              matchInfo->num_exts * sizeof(void*));
  976.         matchInfo->exts[matchInfo->num_exts-1] = newString;
  977.       }
  978.   }
  979. }
  980.  
  981.  
  982. PUBLIC XP_Bool
  983. NET_IsOldMimeTypes (XP_List *masterList)
  984. {
  985.   NET_cdataStruct *cd;
  986.  
  987.   while((cd = XP_ListNextObject(masterList)) != NULL)
  988.     {
  989.       if ( cd->is_local && !cd->is_external )
  990.         { /* This means that this is a old mime types */
  991.           return TRUE;
  992.         }
  993.     }
  994.   return FALSE;
  995. }
  996.  
  997. #ifndef XP_UNIX
  998. static void
  999. net_Real_CleanupFileFormat(char *filename, Bool file_not_open)
  1000. {
  1001.   NET_cdataStruct * cdata;
  1002.   XP_File fp = 0;
  1003.   int len = 0;
  1004.   XP_Bool failed = FALSE;
  1005.   char buffer[512];
  1006.   int i;
  1007.  
  1008.   if(!NET_ciMasterList)
  1009.     return;
  1010.  
  1011.   /* Need to remove from the end so that the next time
  1012.      around, the file will be loaded up into a list in
  1013.      the consistent way */
  1014.   while(!failed && ((cdata = (NET_cdataStruct *)XP_ListRemoveEndObject(NET_ciMasterList)) != NULL))
  1015.     {
  1016.  
  1017.       if(file_not_open &&
  1018.          (cdata->is_external|| cdata->is_modified))
  1019.         {
  1020.           /* open file
  1021.            * if it doesn't open we won't try again
  1022.            */
  1023.           fp = XP_FileOpen(filename? filename : "mime.types",
  1024.                            xpMimeTypes, XP_FILE_WRITE);
  1025.           TRACEMSG(("Writing mime types file..."));
  1026.           file_not_open = FALSE;
  1027.  
  1028.           if(fp)
  1029.             {
  1030.               PR_snprintf(buffer, sizeof(buffer), "#\
  1031. --Netscape Communications Corporation MIME Information\n#\
  1032. Do not delete the above line. It is used to identify the file type.\n#\n");
  1033.               len = XP_FileWrite(buffer, strlen(buffer), fp);
  1034.               if (len != (int) strlen(buffer))
  1035.                 failed = TRUE;
  1036.             }
  1037.         }
  1038.  
  1039.       /* Save out the modfied entries as well */
  1040.       /* cdata might be modified in FE */
  1041.  
  1042.       if((cdata->is_external||cdata->is_modified) && fp)
  1043.         {
  1044.           if(!failed && cdata->ci.type)
  1045.             {
  1046.               PR_snprintf(buffer, sizeof(buffer), "type=%.500s    ",
  1047.                           cdata->ci.type);
  1048.               len = XP_FileWrite(buffer, strlen(buffer), fp);
  1049.               if (len != (int) strlen(buffer))
  1050.                 failed = TRUE;
  1051.             }
  1052.  
  1053.           if(!failed && cdata->ci.encoding)
  1054.             {
  1055.               PR_snprintf(buffer, sizeof(buffer), "enc=%.500s    ",
  1056.                           cdata->ci.encoding);
  1057.               len = XP_FileWrite(buffer, strlen(buffer), fp);
  1058.               if (len != (int) strlen(buffer))
  1059.                 failed = TRUE;
  1060.             }
  1061.  
  1062.           if(!failed && (cdata->num_exts > 0))
  1063.             {
  1064.               PR_snprintf(buffer, sizeof(buffer), "exts=%.500s",
  1065.                           cdata->exts[0]);
  1066.               len = XP_FileWrite(buffer, strlen(buffer), fp);
  1067.               if (len != (int) strlen(buffer))
  1068.                 failed = TRUE;
  1069.  
  1070.               for(i=1; !failed, i<cdata->num_exts; i++)
  1071.                 {
  1072.                   PR_snprintf(buffer, sizeof(buffer), ",%.500s",
  1073.                               cdata->exts[i]);
  1074.                   len = XP_FileWrite(buffer, strlen(buffer), fp);
  1075.                   if (len != (int) strlen(buffer))
  1076.                     failed = TRUE;
  1077.                 }
  1078.  
  1079.               PR_snprintf(buffer, sizeof(buffer), "    ");
  1080.               len = XP_FileWrite(buffer, strlen(buffer), fp);
  1081.               if (len != (int) strlen(buffer))
  1082.                 failed = TRUE;
  1083.             }
  1084.  
  1085.           if(!failed && cdata->ci.icon)
  1086.             {
  1087.               PR_snprintf(buffer, sizeof(buffer), "icon=\"%.500s\"    ",
  1088.                           cdata->ci.icon);
  1089.               len = XP_FileWrite(buffer, strlen(buffer), fp);
  1090.               if (len != (int) strlen(buffer))
  1091.                 failed = TRUE;
  1092.             }
  1093.  
  1094.           if(!failed && cdata->ci.desc)
  1095.             {
  1096.               PR_snprintf(buffer, sizeof(buffer), "desc=\"%.500s\"    ",
  1097.                           cdata->ci.desc);
  1098.               len = XP_FileWrite(buffer, strlen(buffer), fp);
  1099.               if (len != (int) strlen(buffer))
  1100.                 failed = TRUE;
  1101.             }
  1102.  
  1103.           if(!failed && cdata->ci.alt_text)
  1104.             {
  1105.               PR_snprintf(buffer, sizeof(buffer), "alt=\"%.500s\"    ",
  1106.                           cdata->ci.alt_text);
  1107.               len = XP_FileWrite(buffer, strlen(buffer), fp);
  1108.               if (len != (int) strlen(buffer))
  1109.                 failed = TRUE;
  1110.             }
  1111.  
  1112.           PR_snprintf(buffer, sizeof(buffer), "%c", LF);
  1113.           len = XP_FileWrite(buffer, strlen(buffer), fp);
  1114.           if (len != (int) strlen(buffer))
  1115.             failed = TRUE;
  1116.         }
  1117.  
  1118.       /* free the data
  1119.        */
  1120.       NET_cdataFree(cdata);
  1121.     }
  1122.  
  1123.   XP_ListDestroy(NET_ciMasterList);
  1124.   NET_ciMasterList = 0;
  1125.  
  1126.   if(!file_not_open && fp)
  1127.     XP_FileClose(fp);
  1128.   /* This function should really return a return code, and handle any errors */
  1129.  
  1130. }
  1131. #endif /* XP_UNIX */
  1132.  
  1133. #ifdef XP_UNIX
  1134. PUBLIC void
  1135. NET_CleanupFileFormat(char *filename)
  1136. {
  1137.     NET_cdataStruct *cdata;
  1138.     XP_File fp = 0;
  1139.     int len = 0;
  1140.     XP_Bool failed = FALSE;
  1141.     Bool file_open = FALSE;
  1142.     XP_List *modifiedList = NULL;
  1143.     char buffer[512];
  1144.     Bool first = TRUE;
  1145.  
  1146.     if ( !NET_ciMasterList ) return;
  1147.  
  1148.     if ( filename )
  1149.     {
  1150.         fp = XP_FileOpen(filename, xpMimeTypes, XP_FILE_WRITE);
  1151.         /* Need to remove from the end so that the next time
  1152.         around, the file will be loaded up into a list in
  1153.         the consistent way */
  1154.  
  1155.         if ( fp )
  1156.         {
  1157.             file_open = TRUE;
  1158.             modifiedList = XP_ListNew();
  1159.             while((cdata = (NET_cdataStruct *) XP_ListRemoveEndObject(NET_ciMasterList)))
  1160.             {
  1161.                 if ( cdata->is_local )
  1162.                 {
  1163.                     if ( first && !NET_IsOldMimeTypes(NET_ciMasterList) )
  1164.                     {
  1165.                         first = FALSE;
  1166.                         if (cdata->src_string && *cdata->src_string &&
  1167.                             strncmp(cdata->src_string, MCC_MT_MAGIC,
  1168.                             MCC_MT_MAGIC_LEN) &&
  1169.                             strncmp(cdata->src_string, NCC_MT_MAGIC,
  1170.                             NCC_MT_MAGIC_LEN))
  1171.                         {
  1172.                             /* Write out standard new mime type header info */
  1173.                             PR_snprintf(buffer, sizeof(buffer),
  1174.                             "#\
  1175. --Netscape Communications Corporation MIME Information\n#\
  1176. Do not delete the above line. It is used to identify the file type.\n#\n");
  1177.                             len = XP_FileWrite(buffer, strlen(buffer), fp);
  1178.                             if (len != (int) strlen(buffer))
  1179.                                 failed = TRUE;
  1180.                         }
  1181.                     }
  1182.                     if (!failed && cdata->src_string && *cdata->src_string )
  1183.                     {
  1184.                         len = XP_FileWrite(cdata->src_string,
  1185.                             strlen(cdata->src_string), fp);
  1186.  
  1187.                         if (cdata->src_string[strlen(cdata->src_string)-1] != '\n')
  1188.                             len = XP_FileWrite("\n", strlen("\n"), fp);
  1189.                     }
  1190.                     NET_cdataFree(cdata);
  1191.  
  1192.                 }
  1193.                 else if ( cdata->is_modified )
  1194.                     XP_ListAddObject(modifiedList, cdata);
  1195.                 else
  1196.                     NET_cdataFree(cdata);
  1197.  
  1198.             }
  1199.  
  1200.             while (!failed && (cdata = (NET_cdataStruct *) XP_ListRemoveEndObject(modifiedList)))
  1201.             {
  1202.  
  1203.                 if ( first && !NET_IsOldMimeTypes(NET_ciMasterList) )
  1204.                 {
  1205.                     first = FALSE;
  1206.                     if (cdata->src_string && *cdata->src_string &&
  1207.                         strncmp(cdata->src_string, MCC_MT_MAGIC,
  1208.                         MCC_MT_MAGIC_LEN) &&
  1209.                         strncmp(cdata->src_string, NCC_MT_MAGIC,
  1210.                         NCC_MT_MAGIC_LEN))
  1211.                     {
  1212.                         /* Write out standard new mime type header info */
  1213.                         PR_snprintf(buffer, sizeof(buffer),
  1214.                         "#\
  1215. --Netscape Communications Corporation MIME Information\n#\
  1216. Do not delete the above line. It is used to identify the file type.\n#\n");
  1217.                         len = XP_FileWrite(buffer, strlen(buffer), fp);
  1218.                         if (len != (int) strlen(buffer))
  1219.                             failed = TRUE;
  1220.  
  1221.                     }
  1222.                 }
  1223.  
  1224.                 if (!failed && cdata->src_string && *cdata->src_string )
  1225.                 {
  1226.                     len = XP_FileWrite(cdata->src_string,
  1227.                         strlen(cdata->src_string), fp);
  1228.                     if (len != (int) strlen(cdata->src_string))
  1229.                         failed = TRUE;
  1230.                     if ( cdata->src_string[strlen(cdata->src_string)-1] != '\n')
  1231.                     {
  1232.                         len = XP_FileWrite("\n", strlen("\n"), fp);
  1233.                         if (len != (int) strlen("\n"))
  1234.                             failed = TRUE;
  1235.                     }
  1236.                 }
  1237.  
  1238.                 NET_cdataFree(cdata);
  1239.             }
  1240.             XP_FileClose(fp);
  1241.         }
  1242.     }
  1243.     else /* Clean up each node before deleting the root node */
  1244.     {
  1245.         while((cdata = (NET_cdataStruct *) XP_ListRemoveEndObject(NET_ciMasterList)))
  1246.             NET_cdataFree(cdata);
  1247.     }
  1248.     XP_ListDestroy(NET_ciMasterList);
  1249.     NET_ciMasterList = 0;
  1250.     /* This function should really return an error code and deal with any errors when they happen */
  1251. }
  1252.  
  1253. #else /* !XP_UNIX */
  1254.  
  1255. PUBLIC void
  1256. NET_CleanupFileFormat()
  1257. {
  1258.   Bool file_not_open=TRUE;
  1259.   net_Real_CleanupFileFormat(NULL, file_not_open);
  1260. }
  1261.  
  1262. #endif /* !XP_UNIX */
  1263.