home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libnet / mknewsgr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  38.1 KB  |  1,596 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. #include "mkutils.h"
  19. #include "mknewsgr.h"
  20. #include "msgcom.h"
  21. #include "xp_reg.h"
  22. #include "xp_qsort.h"
  23.  
  24. #define DYN_ARRAY_INIT_SIZE 2
  25. #define DYN_ARRAY_GROW_BY   2
  26.  
  27. #define BUFFER_SIZE 2048  /* make sure that this is at least 2048
  28.                            * since I hard coded a reference to it
  29.                            * in an sprintf below :)
  30.                            */
  31.  
  32. typedef struct _SubgroupList SubgroupList;
  33.  
  34. typedef struct _NewsGroupStruct {
  35.     SubgroupList  *children;  /* pointer to longer names */
  36.     char          *name;      /* pointer to subname or NULL 
  37.                                * if it completes there
  38.                                */
  39. } NewsGroupStruct;
  40.  
  41. /* dynamic array struct
  42.  */
  43. struct _SubgroupList {
  44.     int               size;      /* size of */
  45.     NewsGroupStruct  *data;  /* pointer to array of structs */
  46. };
  47.  
  48. PRIVATE char * NET_CurrentlyLoadedHostname = 0;
  49. PRIVATE XP_Bool NET_CurrentlyLoadedListingIsSecure = 0;
  50. PRIVATE Bool NET_NewsgroupsListDirty = FALSE;
  51. PRIVATE time_t NET_NewsGroupsLastUpdate = 0;
  52. PRIVATE SubgroupList *BaseSGStruct=0;
  53. PRIVATE char *large_buffer=0;
  54.  
  55. #if 0    /* unused */
  56. /* Given a group name prefix, like "alt.fan", this will return
  57.    a SubgroupList which points to the groups under that level
  58.    ("addams", "authors", "blues-brothers", etc.)
  59.    If the prefix has no children, 0 is returned.
  60.  */
  61. static SubgroupList *
  62. net_find_group_level (MWContext *context, const char *parent_name)
  63. {
  64.   SubgroupList *sl = BaseSGStruct;
  65.   char *name, *base_name, *dot;
  66.   if (!parent_name || !*parent_name)
  67.     return sl;
  68.   name = XP_STRDUP (parent_name);
  69.   base_name = name;
  70.   if (!name)
  71.     return 0;
  72.  
  73.   while (name && *name)
  74.     {
  75.       /* #### If we can assume the group names are sorted, this could
  76.          do a binary search... */
  77.       int i;
  78.       NewsGroupStruct *ng;
  79.       XP_Bool found = FALSE;
  80.       dot = XP_STRCHR (name, '.');
  81.       if (dot) *dot = 0;
  82.  
  83.       for (i = 0, ng = sl->data; i < sl->size; i++, ng++)
  84.         {
  85.           if (! ng->name)
  86.             break;
  87.           else if (!XP_STRCMP (ng->name, name))
  88.             {
  89.               sl = ng->children;
  90.               found = TRUE;
  91.               break;
  92.             }
  93.         }
  94.       if (! found)
  95.         {
  96.           XP_FREE (base_name);
  97.           return 0;
  98.         }
  99.       name = (dot ? dot + 1 : 0);
  100.     }
  101.   XP_FREE (base_name);
  102.   return sl;
  103. }
  104. #endif /* 0 */
  105.  
  106. static int32
  107. msg_count_descendants (NewsGroupStruct *ng)
  108. {
  109.   int32 kids = 0;
  110.   int32 i;
  111.   if (!ng->children) return 0;
  112.   for (i = 0; i < ng->children->size; i++)
  113.     {
  114.       if (!ng->children->data[i].name) break;
  115.       if (ng->children->data[i].name[0] == 0)
  116.         continue;
  117.       if (ng->children->data[i].children)
  118.         kids += msg_count_descendants (&ng->children->data[i]);
  119.       else
  120.         kids++;
  121.     }
  122.   return kids;
  123. }
  124.  
  125. static NewsGroupStruct *
  126. msg_optimize_single_kid (NewsGroupStruct *ng, char **nameP)
  127. {
  128.   int i, count;
  129.   char *new_name;
  130.   NewsGroupStruct *pkid, *kid;
  131.   if (!ng->children)
  132.     return ng;
  133.  
  134.   for (i = 0, count = 0, pkid = 0, kid = ng->children->data;
  135.        i < ng->children->size && kid->name;
  136.        i++, pkid = kid, kid++)
  137.     {
  138.       if (i == 0 && !*kid->name)
  139.         continue;
  140.       if (++count > 1)
  141.         return ng;
  142.     }
  143.  
  144.   if (!pkid || !pkid->name)
  145.     return ng;
  146.  
  147.   new_name = (char *) XP_ALLOC (XP_STRLEN (*nameP) + XP_STRLEN (pkid->name)
  148.                                 + 3);
  149.   if (!new_name)
  150.     return ng;
  151.   XP_STRCPY (new_name, *nameP);
  152.   XP_STRCAT (new_name, ".");
  153.   XP_STRCAT (new_name, pkid->name);
  154.   *nameP = new_name;
  155.  
  156.   /* We have now taken a newsgroup with a single child and promoted that
  157.      child to this level, prepending to its name.  Now do it again, in
  158.      case that child also had but a single child. */
  159.   {
  160.     char *name2 = new_name;
  161.     NewsGroupStruct *ng2 = msg_optimize_single_kid (pkid, &name2);
  162.     if (ng2 != pkid)
  163.       {
  164.         XP_FREE (new_name);
  165.         *nameP = name2;
  166.         return ng2;
  167.       }
  168.   }
  169.  
  170.   return pkid;
  171. }
  172.  
  173.  
  174. /* #### duplicated in msg.h */
  175. typedef int (*msg_NewsgroupNameMapper) (MWContext *context,
  176.                                         const char *parent_name,
  177.                                         const char *child_name,
  178.                                         XP_Bool group_p,
  179.                                         int32 descendant_group_count,
  180.                                         void *closure);
  181.  
  182. #if 0    /* unused */
  183. /* Given a group name prefix, like "alt.fan", this will map the given
  184.    function over each of the groups under that level ("addams", "authors",
  185.    "blues-brothers", etc.)  If the prefix has no children, it fails, and
  186.    never calls the mapper.  If the mapper returns negative, this function
  187.    fails with that result.
  188.  */
  189. PRIVATE
  190. int
  191. msg_MapNewsgroupNames (MWContext *context,
  192.                        const char *news_host_and_port,
  193.                        XP_Bool     is_secure,
  194.                        const char *name_prefix,
  195.                        msg_NewsgroupNameMapper mapper,
  196.                        void *closure)
  197. {
  198.   int i;
  199.   NewsGroupStruct *ng;
  200.   SubgroupList *sl;
  201.  
  202.   XP_ASSERT (news_host_and_port);
  203.   if (news_host_and_port)
  204.     NET_NewsgroupsLastUpdatedTime ((char*) news_host_and_port, is_secure);
  205.  
  206.   sl = net_find_group_level (context, name_prefix);
  207.   if (!sl)
  208.     return -1;
  209.  
  210.   for (i = 0, ng = sl->data; i < sl->size && ng->name; i++, ng++)
  211.     {
  212.       NewsGroupStruct *ng2 = ng;
  213.       XP_Bool group_p;
  214.       int32 descendant_count;
  215.       int status;
  216.       char *name;
  217.       /* If this is the first time through, and this child has the name "",
  218.          then it indicates that the parent is itself a group - which we
  219.          already know.  So skip it. */
  220.       if (i == 0 && !*ng->name)
  221.         continue;
  222.  
  223.       name = ng->name;
  224.       ng2 = msg_optimize_single_kid (ng, &name);
  225.  
  226.       /* If we found only a single kid, but we are also a group, then
  227.          register us first. */
  228.       if (ng != ng2 && ng->children && ng->children->size > 0 &&
  229.           ng->children->data[0].name && ng->children->data[0].name[0] == 0) {
  230.         status = (*mapper) (context, name_prefix, ng->name, TRUE, 0, closure);
  231.       }
  232.  
  233.       /* This child is itself a group as well as a container if its first
  234.          child has the name "", or if it has no children at all. */
  235.       group_p = (!ng2->children ||
  236.                  (ng2->children->size > 0 &&
  237.                   ng2->children->data[0].name &&
  238.                   ng2->children->data[0].name[0] == 0));
  239.       descendant_count = msg_count_descendants (ng2);
  240.  
  241.       XP_ASSERT(descendant_count != 1); /* because of msg_optimize_single_kid*/
  242.  
  243.       status = (*mapper) (context, name_prefix, name,
  244.                           group_p, descendant_count, closure);
  245.       if (name != ng->name)
  246.         XP_FREE (name);
  247.       if (status < 0) return status;
  248.     }
  249.   return 0;
  250. }
  251. #endif
  252.  
  253. /* this relies on the fact that strtok
  254.  * keeps a copy of the pointer in static memory
  255.  */
  256. PRIVATE
  257. SubgroupList *
  258. net_recursiveNewsGroupStore(char *subname, 
  259.                             Bool  stop_here,
  260.                             SubgroupList * SGptr)
  261. {
  262.     SubgroupList * rv;
  263.     NewsGroupStruct *NGptr;
  264.     int cur_num;
  265.     int len;
  266.  
  267.     if(!SGptr)
  268.       {
  269.         SGptr = XP_NEW(SubgroupList);    /* FIX ME check for NULL here */
  270.         
  271.         if ( SGptr == NULL)
  272.             return NULL;
  273.  
  274.         SGptr->size = DYN_ARRAY_INIT_SIZE;
  275.         SGptr->data = (NewsGroupStruct *)
  276.                             XP_ALLOC(SGptr->size*sizeof(NewsGroupStruct));
  277.  
  278.         if(!SGptr->data)
  279.         {
  280.             SGptr->size = 0;
  281.                return(SGptr);
  282.         }
  283.     
  284.         XP_MEMSET(SGptr->data, 0, SGptr->size*sizeof(NewsGroupStruct));
  285.       }
  286.  
  287.     rv = SGptr;
  288.     cur_num = 0;
  289.     NGptr = &(SGptr->data)[cur_num];
  290.     len = XP_STRLEN(subname);
  291.  
  292.     while(NGptr &&NGptr->name)
  293.       {
  294.  
  295.         if(subname 
  296.             && !XP_STRNCMP(NGptr->name, subname, len)
  297.                 && (NGptr->name[len] == '\0' || NGptr->name[len] == '.'))
  298.           {
  299.             /* move comp.infosystems.www
  300.              * to comp -> infosystems.www
  301.              */
  302.             if(NGptr->name[len] == '.')
  303.               {
  304.                 XP_STRCPY(large_buffer, NGptr->name);
  305.                 NGptr->children = net_recursiveNewsGroupStore(
  306.                                                         (&large_buffer[len])+1,    
  307.                                                         TRUE,    
  308.                                                         NGptr->children);
  309.                 large_buffer[len] = '\0';
  310.                 StrAllocCopy(NGptr->name, large_buffer);
  311.               }
  312.  
  313.             break;
  314.           }
  315.         else
  316.           {
  317.             if(cur_num < SGptr->size-1)
  318.               {
  319.                   NGptr = &(SGptr->data)[++cur_num];
  320.               }
  321.             else
  322.               {
  323.                 if(NGptr->name != NULL)
  324.                     cur_num++; /* increment since the entry is used */
  325.                 NGptr = NULL;
  326.               }
  327.           }
  328.       }
  329.  
  330.     if(!NGptr || !NGptr->name)
  331.       {
  332.         /* need to create a new one
  333.          */
  334.         if(cur_num >= SGptr->size)
  335.           {
  336.             /* grow the dynamic array
  337.              */    
  338.             int prev_size = SGptr->size;
  339.             SGptr->size += DYN_ARRAY_GROW_BY;
  340.             SGptr->data = (NewsGroupStruct *)
  341.                              XP_REALLOC(SGptr->data, 
  342.                                         SGptr->size*sizeof(NewsGroupStruct));
  343.             if (SGptr->data == NULL)
  344.             {
  345.                 SGptr->size = 0;
  346.                 return(SGptr);
  347.             }
  348.  
  349.             /* zero out new fields 
  350.              */
  351.             XP_MEMSET(&(SGptr->data)[prev_size],
  352.                       0,
  353.                       (SGptr->size-prev_size)*sizeof(NewsGroupStruct));
  354.  
  355.           }
  356.  
  357.         NGptr = &(SGptr->data)[cur_num];
  358.  
  359.         if(stop_here)
  360.           {
  361.             /* this is a special case to add a single subname
  362.              * we want to exit here so that we dont
  363.              * call strtok and mess things up.
  364.              */
  365.             StrAllocCopy(NGptr->name, subname);
  366.             return(rv);
  367.           }
  368.  
  369.         /* copy in the whole name not just the sub name
  370.          */
  371.         StrAllocCopy(NGptr->name, subname);
  372.         subname = XP_STRTOK(NULL, "\0");  /* get the rest of the string */
  373.         if(subname)
  374.           {
  375.             StrAllocCat(NGptr->name, ".");
  376.             StrAllocCat(NGptr->name, subname);
  377.             subname = NULL;
  378.           }
  379.       }
  380.     else
  381.       {
  382.         /* otherwise we found an existing one
  383.          */
  384.         subname = XP_STRTOK(NULL, ".");  /* search for more of the string */
  385.  
  386.         if((subname && !NGptr->children)
  387.             || (!subname && NGptr->children) )
  388.             
  389.           {
  390.             /* this means that we have an existing
  391.              * complete group name with the same
  392.              * name as a some of it's childrens heirarcy.
  393.              * we will represent that as a child
  394.              * node with a NULL subname
  395.              */
  396.             NGptr->children = net_recursiveNewsGroupStore("", TRUE, NGptr->children);
  397.           }
  398.         
  399.       }
  400.  
  401.     if(subname)
  402.         NGptr->children = net_recursiveNewsGroupStore(subname, FALSE, NGptr->children);
  403.     
  404.     return(rv);
  405.  
  406. }
  407.  
  408. /* save a newsgroup name
  409.  *
  410.  * will munge the newsgroup passed in for efficiency
  411.  *
  412.  */
  413. MODULE_PRIVATE void
  414. NET_StoreNewsGroup(char * hostname, XP_Bool is_secure, char * newsgroup)
  415. {
  416.     char * subname;
  417.  
  418.     if(!newsgroup)
  419.        return;
  420.  
  421.     if(!large_buffer)
  422.        large_buffer = (char *) XP_ALLOC(BUFFER_SIZE);
  423.     if(!large_buffer)
  424.         return;
  425.  
  426.     subname = XP_STRTOK(newsgroup, ".");
  427.  
  428.     if(subname)
  429.         BaseSGStruct = net_recursiveNewsGroupStore(subname, FALSE, BaseSGStruct);
  430.  
  431.     if(!NET_NewsgroupsListDirty)
  432.       {
  433.         /* if it wasn't dirty before assume this is an update
  434.          */
  435.         NET_NewsGroupsLastUpdate = time(NULL);
  436.         NET_NewsgroupsListDirty = TRUE;
  437.         StrAllocCopy(NET_CurrentlyLoadedHostname, hostname);
  438.         NET_CurrentlyLoadedListingIsSecure = is_secure;
  439.       }
  440.  
  441. }
  442.  
  443. PRIVATE void
  444. net_recursiveFreeNewsGroups(SubgroupList *SGptr)
  445. {
  446.     NewsGroupStruct *NGptr;
  447.     int cur_num=0;
  448.  
  449.     while(cur_num < SGptr->size)
  450.       {
  451.         NGptr = &(SGptr->data)[cur_num++];
  452.  
  453.         FREEIF(NGptr->name);
  454.  
  455.         if(NGptr->children)
  456.             net_recursiveFreeNewsGroups(NGptr->children);
  457.       }
  458.  
  459.     FREE(SGptr);
  460. }
  461.  
  462. MODULE_PRIVATE void
  463. NET_FreeNewsgroups(char *hostname, XP_Bool is_secure)
  464. {
  465.     if(BaseSGStruct)
  466.       {
  467.         net_recursiveFreeNewsGroups(BaseSGStruct);
  468.         BaseSGStruct = 0;
  469.       }
  470.  
  471.     FREEIF(large_buffer);
  472.  
  473.     FREEIF(NET_CurrentlyLoadedHostname);
  474.     NET_CurrentlyLoadedListingIsSecure = 0;
  475.  
  476.     TRACEMSG(("Freeing Newsgroups"));
  477.  
  478. }
  479.  
  480. PRIVATE int
  481. net_NewsGroupsCompar(const void *one,
  482.                      const void *two)
  483. {
  484.     return(XP_STRCMP(((const NewsGroupStruct *)one)->name,
  485.                      ((const NewsGroupStruct *)two)->name));
  486. }
  487.  
  488. PRIVATE void
  489. net_recursiveSortNewsGroups(SubgroupList *SGptr)
  490. {
  491.     NewsGroupStruct *NGptr;
  492.     int total_num=0;
  493.  
  494.     while(total_num < SGptr->size)
  495.       {
  496.         NGptr = &(SGptr->data)[total_num];
  497.  
  498.         if(!NGptr->name)
  499.             break;
  500.  
  501.         total_num++;
  502.       }
  503.  
  504. /*#ifdef XP_MAC*/
  505. #if 0
  506.     qsort(SGptr->data, 
  507.           total_num, 
  508.           sizeof(NewsGroupStruct), 
  509.           (_Cmpfun*)net_NewsGroupsCompar
  510.         );
  511. #else
  512.     XP_QSORT(SGptr->data, 
  513.           total_num, 
  514.           sizeof(NewsGroupStruct), 
  515.          net_NewsGroupsCompar
  516.         );
  517. #endif
  518.  
  519.     while(total_num)
  520.       {
  521.         NGptr = &(SGptr->data)[--total_num];
  522.  
  523.         if(NGptr->children)
  524.             net_recursiveSortNewsGroups(NGptr->children);
  525.       }
  526. }
  527.  
  528. /* sort the newsgroups
  529.  */
  530. MODULE_PRIVATE void
  531. NET_SortNewsgroups(char *hostname, XP_Bool is_secure)
  532. {
  533.     TRACEMSG(("Freeing Newsgroups"));
  534.  
  535.     if(BaseSGStruct)
  536.         net_recursiveSortNewsGroups(BaseSGStruct);
  537. }
  538.  
  539.  
  540. #if 0
  541. PRIVATE
  542. int net_NumberOfGroupsInLevel(SubgroupList *SGptr, 
  543.                               char * search_string,
  544.                               char * name_so_far,
  545.                               Bool   print_all)
  546. {
  547.     int num_at_this_level=0;
  548.     int cur_num=0;
  549.     NewsGroupStruct *NGptr;
  550.  
  551.     /* go through this level once to
  552.      * figure out how many there are
  553.      */
  554.     NGptr = &(SGptr->data)[cur_num++];
  555.  
  556.     while(NGptr->name)
  557.       {
  558.  
  559.         if(print_all)
  560.           {
  561.             num_at_this_level++;
  562.           }
  563.         else
  564.           {
  565.             if(NGptr->children)
  566.                {
  567.                 if(name_so_far)
  568.                     PR_snprintf(large_buffer, BUFFER_SIZE, "%.400s.%.100s.", name_so_far, NGptr->name);
  569.                 else
  570.                     PR_snprintf(large_buffer, BUFFER_SIZE, "%.400s.", NGptr->name);
  571.                }
  572.             else
  573.                {
  574.                 if(name_so_far)
  575.                     PR_snprintf(large_buffer, BUFFER_SIZE, "%.400s.%.100s", name_so_far, NGptr->name);
  576.                 else
  577.                     PR_snprintf(large_buffer, BUFFER_SIZE, "%.400s", NGptr->name);
  578.                }
  579.  
  580. TRACEMSG(("Comparing %s and %s", large_buffer, search_string));
  581.  
  582.             if(!XP_RegExpSearch(large_buffer, search_string))
  583.                 num_at_this_level++;
  584.           }
  585.  
  586.         if(cur_num < SGptr->size)
  587.             NGptr = &(SGptr->data)[cur_num++];
  588.         else
  589.             break;
  590.       }
  591.  
  592. TRACEMSG(("Found %d matches", num_at_this_level));
  593.  
  594.     return(num_at_this_level);
  595. }
  596.  
  597. PRIVATE 
  598. int net_recursiveDisplayNewsgroups(MWContext *context,
  599.                                    SubgroupList    * SGptr,
  600.                                    char            * name_so_far,
  601.                                    char            * search_string,
  602.                                    int             * num_to_display,
  603.                                    Bool              print_all)
  604. {
  605.     NewsGroupStruct *NGptr;
  606.     int cur_num=0;
  607.     int num_in_level=1;
  608.     int rv=0;
  609.     Bool some_printed=FALSE;
  610.     Bool display_this_one=print_all;
  611.     char *new_name_so_far=0;
  612.     
  613.        NGptr = &(SGptr->data)[cur_num++];
  614.  
  615.  
  616.     while(NGptr->name)
  617.       {
  618.  
  619.         if(!print_all)
  620.           {
  621.             if(NGptr->children)
  622.               {
  623.                 if(name_so_far)
  624.                     PR_snprintf(large_buffer, BUFFER_SIZE, "%.400s.%.100s.", name_so_far, NGptr->name);
  625.                 else
  626.                     PR_snprintf(large_buffer, BUFFER_SIZE, "%.400s.", NGptr->name);
  627.               }
  628.             else
  629.               {
  630.                 if(name_so_far)
  631.                     PR_snprintf(large_buffer, BUFFER_SIZE, "%.400s.%.100s", name_so_far, NGptr->name);
  632.                 else
  633.                     PR_snprintf(large_buffer, BUFFER_SIZE, "%.400s", NGptr->name);
  634.               }
  635.  
  636.             if(!XP_RegExpSearch(large_buffer, search_string))
  637.                 display_this_one = TRUE;    
  638.             else
  639.                 display_this_one=FALSE;
  640.           }
  641.  
  642.         if(display_this_one)
  643.           {
  644.             if(!NGptr->children)
  645.               {
  646.  
  647.                 if(*num_to_display > 0)
  648.                     (*num_to_display)--;
  649.  
  650.                 if(!some_printed)
  651.                   {
  652.                     /* INDENT */
  653.                     some_printed = TRUE;
  654.                   }
  655.  
  656.                 if(name_so_far)
  657.                   {
  658.                     if(*NGptr->name)
  659.                         PR_snprintf(large_buffer, BUFFER_SIZE, "%.350s.%.100s", 
  660.                                    name_so_far, NGptr->name);
  661.                     else
  662.                         PR_snprintf(large_buffer, BUFFER_SIZE, "%.400s", name_so_far);
  663.                   }
  664.                 else
  665.                   {
  666.                        PR_snprintf(large_buffer, BUFFER_SIZE, "%.400s", NGptr->name);
  667.                   }
  668.                 rv = MSG_ProcessNewsgroupTree (context,
  669.                                                large_buffer, NGptr->name,
  670.                                                FALSE, FALSE /* #### modp */);
  671.               }
  672.             else 
  673.               {
  674.  
  675.                 if(name_so_far)
  676.                   {
  677.                     StrAllocCopy(new_name_so_far, name_so_far);
  678.                     StrAllocCat(new_name_so_far, ".");
  679.                     StrAllocCat(new_name_so_far, NGptr->name);
  680.                   }
  681.                 else
  682.                   {
  683.                     StrAllocCopy(new_name_so_far, NGptr->name);
  684.                   }
  685.  
  686.                 if(*num_to_display > 0)
  687.                   {
  688.                     num_in_level = net_NumberOfGroupsInLevel(
  689.                                                   NGptr->children,
  690.                                                   search_string,
  691.                                                   new_name_so_far,
  692.                                                   print_all);
  693.  
  694.                     /* take care of really big groups */
  695.                     if(num_in_level > 50)
  696.                         {
  697.                         TRACEMSG(("Only showing one level"));
  698.                         *num_to_display = 1;
  699.                         }
  700.                     else
  701.                         {
  702.                         (*num_to_display) -= (num_in_level-1);
  703.                         if(*num_to_display < 0)
  704.                             *num_to_display = 1;
  705.                         }
  706.                   }
  707.  
  708.                 if(*num_to_display > 0 && num_in_level)
  709.                   {
  710.                     (*num_to_display)--;
  711.  
  712.                     if(!some_printed)
  713.                       {
  714.                         /* #### INDENT */
  715.                         some_printed = TRUE;
  716.                       }
  717.  
  718.                     /* print out the folder */
  719.                     if(name_so_far)
  720.                         PR_snprintf(large_buffer, BUFFER_SIZE, "%.350s.%.100s",
  721.                                    name_so_far, NGptr->name);
  722.                     else
  723.                         PR_snprintf(large_buffer, BUFFER_SIZE, "%.400s", NGptr->name);
  724.  
  725.                     rv = MSG_ProcessNewsgroupTree (context,
  726.                                                    large_buffer, NGptr->name,
  727.                                                    TRUE,
  728.                                                    FALSE /* #### modp */);
  729.  
  730.                     if(rv > -1)
  731.                            rv = net_recursiveDisplayNewsgroups(context,
  732.                                                             NGptr->children, 
  733.                                                new_name_so_far, 
  734.                                                search_string, 
  735.                                                num_to_display, 
  736.                                                display_this_one);
  737.                     }
  738.                 else
  739.                   {
  740.                     if(*num_to_display > 0)
  741.                         (*num_to_display)--;
  742.  
  743.                     if(!some_printed)
  744.                       {
  745.                         /* #### INDENT */
  746.                         some_printed = TRUE;
  747.                       }
  748.  
  749.                     if(name_so_far)
  750.                            PR_snprintf(large_buffer, BUFFER_SIZE, "%.350s.%.100s",
  751.                                    name_so_far, NGptr->name);
  752.                     else
  753.                            PR_snprintf(large_buffer, BUFFER_SIZE, "%.400s", NGptr->name);
  754.                     MSG_ProcessNewsgroupTree (context,
  755.                                               large_buffer, NGptr->name, TRUE,
  756.                                               FALSE /* #### modp */);
  757.                     }
  758.               }
  759.           }
  760.         else if(NGptr->children && *num_to_display > 0)
  761.           {
  762.             if(name_so_far)
  763.               {
  764.                 StrAllocCopy(new_name_so_far, name_so_far);
  765.                 StrAllocCat(new_name_so_far, ".");
  766.                 StrAllocCat(new_name_so_far, NGptr->name);
  767.               }
  768.             else
  769.               {
  770.                 StrAllocCopy(new_name_so_far, NGptr->name);
  771.               }
  772.  
  773.              /* search for more groups
  774.               */
  775.              rv = net_recursiveDisplayNewsgroups(context, NGptr->children,
  776.                                                new_name_so_far,
  777.                                                search_string,
  778.                                                num_to_display,
  779.                                                display_this_one);
  780.           }
  781.  
  782.         if(rv < 0)
  783.             return(rv);
  784.  
  785.         if(cur_num < SGptr->size)
  786.             NGptr = &(SGptr->data)[cur_num++];
  787.         else
  788.             break;
  789.  
  790.       }
  791.  
  792.     if(some_printed)
  793.       {
  794.         /* #### OUTDENT */
  795.       }
  796.  
  797.     return(rv);
  798. }
  799.  
  800. MODULE_PRIVATE int
  801. NET_DisplayNewsgroups(MWContext *context,
  802.                       char * hostname,
  803.                       Bool   is_secure,
  804.                       char            * search_string)
  805. {
  806.     int num_to_display = 300;
  807.     int rv;
  808.     char * new_search_string=0;
  809.  
  810.     if(!large_buffer)
  811.        large_buffer = (char *) XP_ALLOC(BUFFER_SIZE);
  812.     if(!large_buffer)
  813.         return(0);
  814.  
  815.     if(!XP_STRCMP(search_string, "*"))
  816.       {
  817.         num_to_display = 0;
  818.       }
  819.     else 
  820.       {
  821.         char * star = XP_STRCHR(search_string, '*');
  822.  
  823.         if(star && (star-search_string+1 == XP_STRLEN(search_string)))
  824.           {
  825.             /* this is a search of the form "comp.*"
  826.               */
  827.             num_to_display = 300;
  828.           }
  829.         else if(!star)
  830.             {
  831.             /* assume substring match
  832.               * build a new search string
  833.               */
  834.             StrAllocCopy(new_search_string, "*");
  835.             StrAllocCat(new_search_string, search_string);
  836.             StrAllocCat(new_search_string, "*");
  837.             search_string = new_search_string;
  838.             }
  839.       }
  840.  
  841.  
  842.     if(num_to_display > 1)
  843.       {
  844.  
  845.         num_to_display -= net_NumberOfGroupsInLevel(
  846.                                                   BaseSGStruct,
  847.                                                   search_string,
  848.                                                   NULL,
  849.                                                   FALSE);
  850.         if(num_to_display < 0)
  851.             num_to_display = 0;
  852.       }
  853.  
  854.     rv = MSG_InitNewsgroupTree (context);
  855.     if (rv < 0) return rv;
  856.  
  857.     rv = net_recursiveDisplayNewsgroups(context,
  858.                                         BaseSGStruct,
  859.                                              NULL,
  860.                                              search_string,
  861.                                              &num_to_display,
  862.                                              FALSE);
  863.  
  864.     rv = MSG_FinishNewsgroupTree (context);
  865.  
  866.     FREEIF(new_search_string);
  867.  
  868.     return(rv);
  869.  
  870. }
  871. #endif
  872.  
  873. PRIVATE void
  874. net_recursiveSaveNewsGroups(SubgroupList *SGptr, 
  875.                              int           level,
  876.                              XP_File       fp)
  877. {
  878.     NewsGroupStruct *NGptr;
  879.     int cur_num=0;
  880.     int32 len = 0, count = 0;
  881.  
  882.     NGptr = &(SGptr->data)[cur_num++];
  883.  
  884.     while(NGptr->name)
  885.       {
  886.  
  887.         PR_snprintf(large_buffer, BUFFER_SIZE,"%c%.500s%s", '0'+level, NGptr->name, LINEBREAK);
  888.         count = XP_STRLEN(large_buffer);
  889.         len = XP_FileWrite(large_buffer, count, fp);
  890.         if (len != count)
  891.             return;
  892.             
  893.         if(NGptr->children)
  894.           {
  895.             net_recursiveSaveNewsGroups(NGptr->children, level+1, fp);
  896.           }
  897.  
  898.         if(cur_num < SGptr->size)
  899.             NGptr = &(SGptr->data)[cur_num++];
  900.         else
  901.             break;
  902.       }
  903. }
  904.  
  905. MODULE_PRIVATE void
  906. NET_SaveNewsgroupsToDisk(char * hostname, XP_Bool is_secure)
  907. {
  908.     XP_File fp;
  909.     int32 len = 0;
  910.  
  911.     if(!large_buffer)
  912.        large_buffer = (char *) XP_ALLOC(BUFFER_SIZE);
  913.     if(!large_buffer)
  914.         return;
  915.  
  916.     if(!NET_NewsgroupsListDirty)
  917.       {
  918.         TRACEMSG(("It was not neccessary to write the newsgroups to disk"));
  919.         return;
  920.       }
  921.  
  922.     TRACEMSG(("Writing newsgroups to disk"));
  923.  
  924.     fp = XP_FileOpen(hostname, 
  925.                      is_secure ? xpSNewsgroups : xpNewsgroups, 
  926.                      XP_FILE_WRITE_BIN);
  927.  
  928.     if(!fp)
  929.       {
  930.         TRACEMSG(("Could not open output file"));
  931.         return;
  932.       }
  933.  
  934.     len = XP_FileWrite("# Netscape Newsgroups File (", -1, fp);
  935.     XP_FileWrite(hostname, -1, fp);
  936.     XP_FileWrite(")" LINEBREAK "# This is a generated file!  Do not edit."
  937.                  LINEBREAK LINEBREAK, -1, fp);
  938.  
  939.     PR_snprintf(large_buffer, BUFFER_SIZE, "%ld%s", NET_NewsGroupsLastUpdate, LINEBREAK);
  940.     len = XP_FileWrite(large_buffer, XP_STRLEN(large_buffer), fp);
  941.  
  942.     if((len >= 0) && BaseSGStruct)
  943.         net_recursiveSaveNewsGroups(BaseSGStruct, 0, fp);
  944.  
  945.     NET_NewsgroupsListDirty = FALSE;
  946.  
  947.     XP_FileClose(fp);
  948. }
  949.  
  950. PRIVATE
  951. SubgroupList *
  952. net_RecursiveNewsgroupsDiskRead(SubgroupList * SGptr,
  953.                                 int            cur_level,
  954.                                 int             *cur_line,
  955.                                 XP_File        fp)
  956. {
  957.     SubgroupList * rv = SGptr;
  958.     SubgroupList * newSGptr;
  959.     NewsGroupStruct *NGptr=NULL;
  960.     int file_level;
  961.     int cur_num;
  962.     char * subname;
  963.  
  964.     if(!SGptr)
  965.       {
  966.         SGptr = XP_NEW(SubgroupList);
  967.  
  968.         if(!SGptr)
  969.             return(NULL);
  970.  
  971.         SGptr->size = DYN_ARRAY_INIT_SIZE;
  972.         SGptr->data = (NewsGroupStruct *)
  973.                             XP_ALLOC(SGptr->size*sizeof(NewsGroupStruct));
  974.  
  975.         if(!SGptr->data)
  976.         {
  977.             SGptr->size = 0;
  978.             return(SGptr);
  979.         }
  980.    
  981.         XP_MEMSET(SGptr->data, 0, SGptr->size*sizeof(NewsGroupStruct));
  982.  
  983.         rv = SGptr;
  984.       }
  985.  
  986.     /* assume an existing buffer of data 
  987.      */
  988.     while(1)
  989.       {
  990.         if(!*large_buffer)
  991.             return rv;  /* buffer empty means file done */
  992.  
  993.         file_level = (*large_buffer)-'0';
  994.     
  995.         if(file_level < cur_level)
  996.             return(rv);
  997.  
  998.         if(file_level > cur_level)
  999.           {
  1000.             newSGptr = net_RecursiveNewsgroupsDiskRead(
  1001.                                 NGptr ? NGptr->children : NULL,
  1002.                                 cur_level+1,
  1003.                                 cur_line,
  1004.                                 fp);
  1005.  
  1006.             if(NGptr)
  1007.               {
  1008.                 NGptr->children = newSGptr;
  1009.               }
  1010.             else
  1011.               {
  1012.                 TRACEMSG(("ERROR in newsgroups file (1)"));
  1013.               }
  1014.  
  1015.             file_level = (*large_buffer)-'0';
  1016.             if(file_level < cur_level)
  1017.               {
  1018.                 return(rv);
  1019.               }
  1020.             else
  1021.               {
  1022.                 /* new line was gotten in recursion */
  1023.                 continue; 
  1024.               }
  1025.           }
  1026.  
  1027.         /* add this subname to the current level
  1028.          */
  1029.         subname = large_buffer+1;
  1030.         cur_num = 0;
  1031.         NGptr = &(SGptr->data)[cur_num];
  1032.  
  1033.         /* find last name and add to the bottom
  1034.          */
  1035.         while(NGptr && NGptr->name)
  1036.             {
  1037.             /* assume no duplicates
  1038.              */
  1039.             if(cur_num < SGptr->size-1)
  1040.               {
  1041.                    NGptr = &(SGptr->data)[++cur_num];
  1042.               }
  1043.             else
  1044.               {
  1045.                 if(NGptr->name != NULL)
  1046.                     cur_num++; /* increment since the entry is used */
  1047.                 NGptr = NULL;
  1048.               }
  1049.           }
  1050.  
  1051.         /* grow the dyn array if neccessary
  1052.          */
  1053.         if(cur_num >= SGptr->size)
  1054.           {
  1055.             /* grow the dynamic array
  1056.              */    
  1057.             int prev_size = SGptr->size;
  1058.             SGptr->size += DYN_ARRAY_GROW_BY;
  1059.             SGptr->data = (NewsGroupStruct *)
  1060.                                  XP_REALLOC(SGptr->data, 
  1061.                                         SGptr->size*sizeof(NewsGroupStruct));
  1062.  
  1063.             if(!SGptr->data)
  1064.             {
  1065.                 SGptr->size = 0;
  1066.                 return(SGptr);
  1067.             }
  1068.  
  1069.             /* zero out new fields 
  1070.              */
  1071.             XP_MEMSET(&(SGptr->data)[prev_size],
  1072.                           0,
  1073.                           (SGptr->size-prev_size)*sizeof(NewsGroupStruct));
  1074.  
  1075.           }
  1076.  
  1077.         /* create a new name
  1078.          */
  1079.         NGptr = &(SGptr->data)[cur_num];
  1080.         StrAllocCopy(NGptr->name, subname);
  1081.  
  1082.         if(!XP_FileReadLine(large_buffer, BUFFER_SIZE, fp))
  1083.           {
  1084.             *large_buffer = 0;
  1085.             return(rv);
  1086.           }
  1087.  
  1088.         XP_StripLine(large_buffer);
  1089.         (*cur_line)++;
  1090.       }
  1091.  
  1092.     assert(0);
  1093.     return(rv);
  1094.  
  1095. }
  1096.  
  1097. MODULE_PRIVATE time_t
  1098. NET_ReadNewsgroupsFromDisk(char *hostname, XP_Bool is_secure)
  1099. {
  1100.  
  1101.     XP_File fp;
  1102.     int cur_line=3;
  1103.  
  1104.     /* probably won't do anything
  1105.      */
  1106.     NET_SaveNewsgroupsToDisk(hostname, is_secure);
  1107.     NET_FreeNewsgroups(hostname, is_secure);
  1108.  
  1109.     if(!large_buffer)
  1110.        large_buffer = (char *) XP_ALLOC(BUFFER_SIZE);
  1111.     if(!large_buffer)
  1112.         return(0);
  1113.  
  1114.     TRACEMSG(("Reading Newsgroups from disk"));
  1115.  
  1116.     fp = XP_FileOpen(hostname, 
  1117.                      is_secure ? xpSNewsgroups : xpNewsgroups, 
  1118.                      XP_FILE_READ_BIN);
  1119.  
  1120.     if(!fp)
  1121.       {
  1122.         TRACEMSG(("Could not open input file"));
  1123.         return(0);
  1124.       }
  1125.  
  1126.     /* skip first line */
  1127.     if(!XP_FileReadLine(large_buffer, BUFFER_SIZE, fp))
  1128.       return(0);
  1129.     TRACEMSG(("Read newsgroups cookie: %s", large_buffer));
  1130.  
  1131.     /* skip comment and blank lines at beginning. */
  1132.     while (1)
  1133.       {
  1134.         if(!XP_FileReadLine(large_buffer, BUFFER_SIZE, fp))
  1135.           return(0);
  1136.         if (large_buffer[0] != '#' && large_buffer[0] != CR &&
  1137.             large_buffer[0] != LF  && large_buffer[0] != 0)
  1138.           break;
  1139.       }
  1140.  
  1141.     TRACEMSG(("Read newsgroups last mod date: %s", large_buffer));
  1142.  
  1143.     NET_NewsGroupsLastUpdate = atol(large_buffer);
  1144.  
  1145.     /* get the first line to be passed in
  1146.      */
  1147.     if(!XP_FileReadLine(large_buffer, BUFFER_SIZE, fp))
  1148.         return(0);
  1149.  
  1150.     XP_StripLine(large_buffer);
  1151.  
  1152.     BaseSGStruct = net_RecursiveNewsgroupsDiskRead(BaseSGStruct, 0, &cur_line, fp);
  1153.  
  1154.     XP_FileClose(fp);
  1155.  
  1156.     StrAllocCopy(NET_CurrentlyLoadedHostname, hostname);
  1157.     NET_CurrentlyLoadedListingIsSecure = is_secure;
  1158.  
  1159.     return(NET_NewsGroupsLastUpdate);
  1160. }
  1161.  
  1162. MODULE_PRIVATE time_t
  1163. NET_NewsgroupsLastUpdatedTime(char * hostname, XP_Bool is_secure)
  1164. {
  1165.     if(NET_CurrentlyLoadedHostname && hostname)
  1166.       {
  1167.          if(strcasecomp(hostname, NET_CurrentlyLoadedHostname)
  1168.             || is_secure != NET_CurrentlyLoadedListingIsSecure)
  1169.             NET_FreeNewsgroups(hostname, is_secure);
  1170.       }
  1171.  
  1172.     if(NET_CurrentlyLoadedHostname)
  1173.         return(NET_NewsGroupsLastUpdate);
  1174.     else
  1175.         return(NET_ReadNewsgroupsFromDisk(hostname, is_secure));
  1176. }
  1177.  
  1178. /* UNIX doesn't need this stuff since it uses the file system
  1179.  * to store the mappings as filenames
  1180.  */
  1181.  
  1182. XP_List *HostMapList=0;
  1183. Bool NewsrcMapDirty=FALSE;     
  1184.  
  1185. typedef struct _NewsrcHostMap {
  1186.     char * filename;
  1187.     char * psuedo_name;
  1188.     Bool   is_newsgroups_file;    /* This was Bool * */
  1189. } NewsrcHostMap;
  1190.  
  1191. /* register a newsrc file mapping
  1192.  */
  1193. PUBLIC Bool
  1194. NET_RegisterNewsrcFile(char * filename, 
  1195.                        char *hostname, 
  1196.                        Bool is_secure,
  1197.                        Bool is_newsgroups_file)
  1198. {
  1199.     NewsrcHostMap *host_map_struct = XP_NEW(NewsrcHostMap);
  1200.     XP_List * list_prt;
  1201.     NewsrcHostMap *tmp_host_map_struct;
  1202.  
  1203.     if(!host_map_struct)
  1204.         return(FALSE);
  1205.  
  1206.     XP_MEMSET(host_map_struct, 0, sizeof(NewsrcHostMap));
  1207.     
  1208.     /* you losers, there's no such thing as XP_Assert in xfe!! */
  1209.     assert(filename);
  1210.     assert(hostname);
  1211.  
  1212.     if(is_secure)
  1213.         StrAllocCopy(host_map_struct->psuedo_name, "snewsrc-");
  1214.     else
  1215.         StrAllocCopy(host_map_struct->psuedo_name, "newsrc-");
  1216.  
  1217.     StrAllocCat(host_map_struct->psuedo_name, hostname);
  1218.  
  1219.     StrAllocCopy(host_map_struct->filename, filename);
  1220.  
  1221.     host_map_struct->is_newsgroups_file = is_newsgroups_file;
  1222.  
  1223.     if(!HostMapList)
  1224.         HostMapList = XP_ListNew();
  1225.  
  1226.     if(!HostMapList)
  1227.         return(FALSE);
  1228.  
  1229.     NewsrcMapDirty = TRUE;
  1230.  
  1231.     /* search for duplicate mappings */
  1232.     list_prt = HostMapList;
  1233.     while((tmp_host_map_struct = (NewsrcHostMap *)XP_ListNextObject(list_prt)) != NULL)
  1234.       {
  1235.         if(tmp_host_map_struct->is_newsgroups_file == is_newsgroups_file
  1236.             && !strcasecomp(tmp_host_map_struct->psuedo_name, 
  1237.                                host_map_struct->psuedo_name))
  1238.           {
  1239.             XP_ListRemoveObject(HostMapList, tmp_host_map_struct);
  1240.             FREEIF(tmp_host_map_struct->psuedo_name);
  1241.             FREEIF(tmp_host_map_struct->filename);
  1242.             FREE(tmp_host_map_struct);
  1243.  
  1244.             break; /* end search */
  1245.           }
  1246.       }
  1247.  
  1248.     XP_ListAddObject(HostMapList, host_map_struct);
  1249.  
  1250.     NET_SaveNewsrcFileMappings();
  1251.  
  1252.     return(TRUE);
  1253. }
  1254.  
  1255. /* removes a newshost to file mapping.  Removes both
  1256.  * the newsrc and the newsgroups mapping
  1257.  * this function does not remove the actual files,
  1258.  * that is left up to the caller
  1259.  */
  1260. PUBLIC void
  1261. NET_UnregisterNewsHost(const char *host, 
  1262.                        Bool is_secure)
  1263. {
  1264.     XP_List * list_prt = HostMapList;
  1265.     NewsrcHostMap *host_map_struct;
  1266.     char *hostname;
  1267.  
  1268.     XP_ASSERT(host);
  1269.  
  1270.     if(!host)
  1271.         return;
  1272.  
  1273.     /* Run through the entire list and remove all entries that
  1274.      * match that hostname
  1275.      */
  1276.     while((host_map_struct = (NewsrcHostMap *)XP_ListNextObject(list_prt)) != NULL)
  1277.       {
  1278.  
  1279.         if(is_secure && *host_map_struct->psuedo_name != 's')
  1280.             continue;
  1281.  
  1282.         if(!is_secure && *host_map_struct->psuedo_name == 's')
  1283.             continue;
  1284.  
  1285.         hostname = XP_STRCHR(host_map_struct->psuedo_name, '-');
  1286.  
  1287.         if(!hostname)
  1288.             continue;
  1289.  
  1290.         hostname++;
  1291.  
  1292.         if(strcasecomp(hostname, host))
  1293.             continue;
  1294.  
  1295.         XP_ListRemoveObject(HostMapList, host_map_struct);
  1296.  
  1297.         NewsrcMapDirty = TRUE;
  1298.  
  1299.         /* free the data */
  1300.         FREEIF(host_map_struct->psuedo_name);
  1301.         FREEIF(host_map_struct->filename);
  1302.         FREE(host_map_struct);
  1303.  
  1304.         /* we must start over in the list because the
  1305.          * act of removeing an item will cause purity
  1306.          * errors if we don't start over
  1307.          */
  1308.         list_prt = HostMapList;
  1309.       }
  1310.     NET_SaveNewsrcFileMappings();
  1311. }
  1312.  
  1313. /* map a filename and security status into a filename
  1314.  *
  1315.  * returns NULL on error or no mapping.
  1316.  */
  1317. PUBLIC char *
  1318. NET_MapNewsrcHostToFilename(char * host, 
  1319.                             Bool is_secure, 
  1320.                             Bool is_newsgroups_file)
  1321. {
  1322.     XP_List * list_prt = HostMapList;
  1323.     NewsrcHostMap *host_map_struct;
  1324.     char *hostname;
  1325.  
  1326.     while((host_map_struct = (NewsrcHostMap *)XP_ListNextObject(list_prt)) != NULL)
  1327.       {
  1328.         if(is_newsgroups_file != host_map_struct->is_newsgroups_file)
  1329.             continue;
  1330.  
  1331.         if(is_secure && *host_map_struct->psuedo_name != 's')
  1332.             continue;
  1333.         
  1334.         if(!is_secure && *host_map_struct->psuedo_name == 's')
  1335.             continue;
  1336.  
  1337.         hostname = XP_STRCHR(host_map_struct->psuedo_name, '-');
  1338.         
  1339.         if(!hostname)
  1340.             continue;
  1341.  
  1342.         hostname++;
  1343.  
  1344.         if(strcasecomp(hostname, host))
  1345.             continue;
  1346.  
  1347.         return(host_map_struct->filename);
  1348.  
  1349.       }
  1350.  
  1351.     return(NULL);
  1352. }
  1353.  
  1354. #define NEWSRC_MAP_FILE_COOKIE "netscape-newsrc-map-file"
  1355.  
  1356. /* save newsrc file mappings from memory onto disk
  1357.  */
  1358. PUBLIC Bool
  1359. NET_SaveNewsrcFileMappings()
  1360. {
  1361.     XP_List * list_prt = HostMapList;
  1362.     NewsrcHostMap *host_map_struct;
  1363.     XP_File fp;
  1364.     int32 len = 0;
  1365.  
  1366.     if(!NewsrcMapDirty)
  1367.         return(TRUE);
  1368.  
  1369.     if(!(fp = XP_FileOpen("", xpNewsrcFileMap, XP_FILE_WRITE_BIN)))
  1370.       {
  1371.         return(FALSE);
  1372.       }
  1373.  
  1374.     len = XP_FileWrite(NEWSRC_MAP_FILE_COOKIE, XP_STRLEN(NEWSRC_MAP_FILE_COOKIE), fp);
  1375.     if (len < 0)
  1376.     {
  1377.         XP_FileClose(fp);
  1378.         return FALSE;
  1379.     }
  1380.     XP_FileWrite(LINEBREAK, XP_STRLEN(LINEBREAK), fp);
  1381.  
  1382.     while((host_map_struct = (NewsrcHostMap *)XP_ListNextObject(list_prt)) != NULL)
  1383.       {
  1384.  
  1385.         XP_FileWrite(host_map_struct->psuedo_name, 
  1386.                      XP_STRLEN(host_map_struct->psuedo_name),
  1387.                      fp);
  1388.         
  1389.         XP_FileWrite("\t", 1, fp);
  1390.  
  1391.         XP_FileWrite(host_map_struct->filename, 
  1392.                      XP_STRLEN(host_map_struct->filename),
  1393.                      fp);
  1394.         
  1395.         XP_FileWrite("\t", 1, fp);
  1396.  
  1397.         if(host_map_struct->is_newsgroups_file)
  1398.             XP_FileWrite("TRUE", 4, fp);
  1399.         else
  1400.             XP_FileWrite("FALSE", 5, fp);
  1401.  
  1402.         len = XP_FileWrite(LINEBREAK, XP_STRLEN(LINEBREAK), fp);
  1403.         if (len < 0)
  1404.         {
  1405.             XP_FileClose(fp);
  1406.             return FALSE;
  1407.         }
  1408.       }
  1409.  
  1410.     XP_FileClose(fp);
  1411.  
  1412.     NewsrcMapDirty = FALSE;
  1413.  
  1414.     return(TRUE);
  1415. }
  1416.  
  1417. /* read newsrc file mappings from disk into memory
  1418.  */
  1419. PUBLIC Bool
  1420. NET_ReadNewsrcFileMappings()
  1421. {
  1422.     XP_File fp;
  1423.     char buffer[512];
  1424.     char psuedo_name[512];
  1425.     char filename[512];
  1426.     char is_newsgroup[512];
  1427.     NewsrcHostMap * hs_struct;
  1428.  
  1429.     if(!(fp = XP_FileOpen("", xpNewsrcFileMap, XP_FILE_READ_BIN)))
  1430.       {
  1431.         return(FALSE);
  1432.       }
  1433.  
  1434.     if(!HostMapList)
  1435.         HostMapList = XP_ListNew();
  1436.  
  1437.     /* get the cookie and ignore */
  1438.     XP_FileReadLine(buffer, sizeof(buffer), fp);
  1439.  
  1440.     while(XP_FileReadLine(buffer, sizeof(buffer), fp))
  1441.       {
  1442.         char * p;
  1443.         int i;
  1444.  
  1445.         hs_struct = XP_NEW(NewsrcHostMap);
  1446.  
  1447.         if(!hs_struct)
  1448.             return(FALSE);
  1449.  
  1450.         XP_MEMSET(hs_struct, 0, sizeof(NewsrcHostMap));
  1451.  
  1452.         /*
  1453.             This used to be scanf() call which would incorrectly
  1454.             parse long filenames with spaces in them.  - JRE
  1455.         */
  1456.  
  1457.         filename[0] = '\0';
  1458.         is_newsgroup[0]='\0';
  1459.  
  1460.         for (i = 0, p = buffer; *p && *p != '\t' && i < 500; p++, i++)
  1461.             psuedo_name[i] = *p;
  1462.         psuedo_name[i] = '\0';
  1463.         if (*p) 
  1464.           {
  1465.             for (i = 0, p++; *p && *p != '\t' && i < 500; p++, i++)
  1466.                 filename[i] = *p;
  1467.             filename[i]='\0';
  1468.             if (*p) 
  1469.               {
  1470.                 for (i = 0, p++; *p && *p != '\r' && i < 500; p++, i++)
  1471.                     is_newsgroup[i] = *p;
  1472.                 is_newsgroup[i]='\0';
  1473.               }
  1474.           }
  1475.  
  1476.         StrAllocCopy(hs_struct->psuedo_name, psuedo_name);
  1477.         StrAllocCopy(hs_struct->filename, filename);
  1478.  
  1479.         if(!XP_STRNCMP(is_newsgroup, "TRUE", 4))
  1480.             hs_struct->is_newsgroups_file = TRUE;
  1481.  
  1482.         XP_ListAddObject(HostMapList, hs_struct);        
  1483.       }
  1484.  
  1485.  
  1486.     XP_FileClose(fp);
  1487.  
  1488.     return(TRUE);
  1489. }
  1490.  
  1491. PUBLIC void 
  1492. NET_FreeNewsrcFileMappings(void)
  1493. {
  1494.     NewsrcHostMap *host_map_struct;
  1495.  
  1496.     while((host_map_struct = (NewsrcHostMap *)XP_ListRemoveTopObject(HostMapList)) != NULL)
  1497.       {
  1498.         FREEIF(host_map_struct->psuedo_name);
  1499.         FREEIF(host_map_struct->filename);
  1500.         FREE(host_map_struct);
  1501.       }
  1502. }
  1503.  
  1504.  
  1505. #if defined(DEBUG) && defined(XP_UNIX)
  1506.  
  1507. PUBLIC void
  1508. TestNewsrcFileMappings(void)
  1509. {
  1510.  
  1511.   printf("secure flop maps to: %s\n", NET_MapNewsrcHostToFilename("flop", TRUE, FALSE));
  1512.   printf("insec flop maps to: %s\n", NET_MapNewsrcHostToFilename("flop", FALSE, FALSE));
  1513.   printf("insec news maps to: %s\n", NET_MapNewsrcHostToFilename("news", FALSE, FALSE));
  1514.  
  1515.   NET_RegisterNewsrcFile("newsrc-flop", "flop", FALSE, FALSE);
  1516.   NET_RegisterNewsrcFile("snewsrc-flop", "flop", TRUE, FALSE);
  1517.   NET_RegisterNewsrcFile("newsrc-news", "news", FALSE, FALSE);
  1518.  
  1519.   printf("secure flop maps to: %s\n", NET_MapNewsrcHostToFilename("flop", TRUE, FALSE));
  1520.   printf("insec flop maps to: %s\n", NET_MapNewsrcHostToFilename("flop", FALSE, FALSE));
  1521.   printf("insec news maps to: %s\n", NET_MapNewsrcHostToFilename("news", FALSE, FALSE));
  1522.  
  1523.     printf("saving mappings\n");
  1524.   NET_SaveNewsrcFileMappings();
  1525.     printf("freeing mappings\n");
  1526.   NET_FreeNewsrcFileMappings();
  1527.     printf("reading mappings\n");
  1528.   NET_ReadNewsrcFileMappings();
  1529.   
  1530.   printf("adding duplicates\n");
  1531.   NET_RegisterNewsrcFile("newsrc-flop", "flop", FALSE, FALSE);
  1532.   NET_RegisterNewsrcFile("snewsrc-flop", "flop", TRUE, FALSE);
  1533.   NET_RegisterNewsrcFile("newsrc-news", "news", FALSE, FALSE);
  1534.  
  1535.   printf("secure flop maps to: %s\n", NET_MapNewsrcHostToFilename("flop", TRUE, FALSE));
  1536.   printf("insec flop maps to: %s\n", NET_MapNewsrcHostToFilename("flop", FALSE, FALSE));
  1537.   printf("insec news maps to: %s\n", NET_MapNewsrcHostToFilename("news", FALSE, FALSE));
  1538. }
  1539. #endif
  1540.  
  1541. /* XP_GetNewsRCFiles returns a null terminated array
  1542.  * of pointers to malloc'd filename's.  Each filename
  1543.  * represents a different newsrc file.
  1544.  *
  1545.  * return only the filename since the path is not needed
  1546.  * or wanted.
  1547.  *
  1548.  * Netlib is expecting a string of the form:
  1549.  *  [s]newsrc-host.name.domain[:port]
  1550.  *
  1551.  * examples:
  1552.  *    newsrc-news.mcom.com
  1553.  *    snewsrc-flop.mcom.com
  1554.  *    newsrc-news.mcom.com:118
  1555.  *    snewsrc-flop.mcom.com:1191
  1556.  *
  1557.  * the port number is optional and should only be
  1558.  * there when different from the default.
  1559.  * the "s" in front of newsrc signifies that
  1560.  * security is to be used.
  1561.  *
  1562.  * return NULL on critical error or no files
  1563.  */                                   
  1564. #if !defined(XP_UNIX) 
  1565. PUBLIC char ** XP_GetNewsRCFiles(void)
  1566. {
  1567.     /* @@@ max number of newsrc's is 512
  1568.      */
  1569.     char ** rv = (char **)XP_ALLOC(sizeof(char*)*512);
  1570.     XP_List * list_prt = HostMapList;
  1571.     NewsrcHostMap *host_map_struct;
  1572.     int count=0;
  1573.  
  1574.     if(!rv)
  1575.         return(NULL);
  1576.  
  1577.     XP_MEMSET(rv, 0, sizeof(char*)*512);
  1578.  
  1579.     while((host_map_struct = (NewsrcHostMap *)XP_ListNextObject(list_prt)) != NULL)
  1580.       {
  1581.  
  1582.         if(host_map_struct->is_newsgroups_file)
  1583.             continue;
  1584.  
  1585.         StrAllocCopy(rv[count++], host_map_struct->psuedo_name);
  1586.  
  1587.         if(count >= 510)
  1588.             break;
  1589.       }
  1590.  
  1591.     return(rv);
  1592. }
  1593. #endif /* UNIX */
  1594.  
  1595.  
  1596.