config.c
上传用户:seven77cht
上传日期:2007-01-04
资源大小:486k
文件大小:92k
源码类别:

浏览器

开发平台:

Unix_Linux

  1. /***************************************
  2.   $Header: /home/amb/wwwoffle/RCS/config.c 2.80 2000/01/22 13:26:22 amb Exp $
  3.   WWWOFFLE - World Wide Web Offline Explorer - Version 2.5d.
  4.   Configuration file management functions.
  5.   ******************/ /******************
  6.   Written by Andrew M. Bishop
  7.   This file Copyright 1997,98,99,2000 Andrew M. Bishop
  8.   It may be distributed under the GNU Public License, version 2, or
  9.   any higher version.  See section COPYING of the GNU Public license
  10.   for conditions under which this file may be redistributed.
  11.   ***************************************/
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16. #include <limits.h>
  17. #include <unistd.h>
  18. #include <sys/types.h>
  19. #include <sys/stat.h>
  20. #include <sys/utsname.h>
  21. #include <dirent.h>
  22. #include <pwd.h>
  23. #include <grp.h>
  24. #include "misc.h"
  25. #include "config.h"
  26. #include "proto.h"
  27. #include "sockets.h"
  28. #include "errors.h"
  29. #include "wwwoffle.h"
  30. #ifndef SPOOL_DIR
  31. #define SPOOL_DIR DEF_SPOOL
  32. #endif
  33. #ifndef CONF_DIR
  34. #define CONF_DIR DEF_CONF
  35. #endif
  36. /* Type definitions */
  37. /*+ The type of value to expect for a value. +*/
  38. typedef enum _ConfigType
  39. {
  40.  Fixed,                         /*+ When the left hand side is fixed. +*/
  41.  None,                          /*+ When there is no right hand side. +*/
  42.  CfgMaxServers,                 /*+ Max number of servers to fork (>0, <MAX_SERVERS). +*/
  43.  CfgMaxFetchServers,            /*+ Max number of servers for fetching pages (>0, <MAX_FETCH_SERVERS). +*/
  44.  CfgLogLevel,                   /*+ A log level (debug, info, important, warning or fatal). +*/
  45.  Boolean,                       /*+ A boolean response (yes/no 1/0 true/false). +*/
  46.  PortNumber,                    /*+ For port numbers (>0). +*/
  47.  AgeDays,                       /*+ An age in days (can be -ve). +*/
  48.  TimeSecs,                      /*+ A time in seconds (can be -ve). +*/
  49.  CacheSize,                     /*+ The cache size (must be >=0). +*/
  50.  FileSize,                      /*+ A file size (must be >=0) +*/
  51.  Percentage,                    /*+ A percentage (must be >=0 and <=100) +*/
  52.  UserId,                        /*+ For user IDs, (numeric or string). +*/
  53.  GroupId,                       /*+ For group IDs, (numeric or string). +*/
  54.  String,                        /*+ For an arbitrary string. +*/
  55.  PathName,                      /*+ For pathname values (string starting with '/'). +*/
  56.  FileExt,                       /*+ A file extension (.string). +*/
  57.  FileMode,                      /*+ The mode for dir/file creation. +*/
  58.  MIMEType,                      /*+ A MIME type (string/string). +*/
  59.  Host,                          /*+ For host names (string). +*/
  60.  HostAndPort,                   /*+ For host name and port numbers (string[:port]). +*/
  61.  HostAndPortOrNone,             /*+ For host name and port numbers (string[:port]) or nothing. +*/
  62.  UserPass,                      /*+ A username and password (string:string) +*/
  63.  Url,                           /*+ For a URL ([proto://host[:port]]/path). +*/
  64.  OptionalUrl,                   /*+ For an optional URL ([proto://host[:port]]/path). +*/
  65.  UrlSpecification               /*+ A URL specification as described in README.CONF. +*/
  66. }
  67. ConfigType;
  68. /*+ A description of an entry in a section of the config file. +*/
  69. typedef struct _Entry
  70. {
  71.  char *name;                    /*+ The name of the entry. +*/
  72.  void *pointer;                 /*+ A pointer to the value of the entry. +*/
  73.  char list;                     /*+ Set to true if it is a list of KeyPairs. +*/
  74.  ConfigType left_type;          /*+ The type of the left side of the equals sign. +*/
  75.  ConfigType right_type;         /*+ The type of the right side of the equals sign. +*/
  76. }
  77. Entry;
  78. /*+ A description of a section in the config file. +*/
  79. typedef struct _Section
  80. {
  81.  char *name;                    /*+ The name of the section. +*/
  82.  Entry *entries;                /*+ The entries in the section (NULL terminated). +*/
  83. }
  84. Section;
  85. /*+ A URL-SPECIFICATION as described in README.CONF. +*/
  86. typedef struct _UrlSpec
  87. {
  88.  int negated;                   /*+ Set to true if this is a negated URL-SPECIFICATION +*/
  89.  char *proto;                   /*+ The protocol (or NULL). +*/
  90.  char *host;                    /*+ The hostname (or NULL). +*/
  91.  int port;                      /*+ The port number (or 0 or -1). +*/
  92.  char *path;                    /*+ The pathname (or NULL). +*/
  93.  char *args;                    /*+ The arguments (or NULL) +*/
  94. }
  95. UrlSpec;
  96. /*+ A key or a value. +*/
  97. typedef union _KeyOrValue
  98. {
  99.  char    *string;               /*+ A string value. +*/
  100.  int      integer;              /*+ An integer value. +*/
  101.  UrlSpec *urlspec;              /*+ A URL-SPECIFICATION +*/
  102. }
  103. KeyOrValue;
  104. /*+ A key and value pair. +*/
  105. typedef struct _KeyPair
  106. {
  107.  KeyOrValue key;                /*+ The key. +*/
  108.  KeyOrValue value;              /*+ The value. +*/
  109. }
  110. KeyPair;
  111. /*+ The last of a KeyPair list. +*/
  112. static KeyPair KeyPairEnd;
  113. /* StartUp section */
  114. /*+ The name of the configuration file. +*/
  115. char *ConfigFile=CONF_DIR "/wwwoffle.conf";
  116. /*+ The port number to use for the HTTP proxy port. +*/
  117. int HTTP_Port=DEF_HTTP_PORT;
  118. /*+ The port number to use for the wwwoffle port. +*/
  119. int WWWOFFLE_Port=DEF_WWWOFFLE_PORT;
  120. /*+ The spool directory. +*/
  121. char *SpoolDir=SPOOL_DIR;
  122. /*+ The user id for wwwoffled or -1 for none. +*/
  123. int WWWOFFLE_Uid=-1;
  124. /*+ The group id for wwwoffled or -1 for none. +*/
  125. int WWWOFFLE_Gid=-1;
  126. /*+ Whether to use the syslog facility or not. +*/
  127. int UseSyslog=1;
  128. /*+ The password required for demon configuration. +*/
  129. char *PassWord=NULL;
  130. /*+ Maximum number of servers  +*/
  131. int MaxServers=DEF_MAX_SERVERS; /*+ in total. +*/
  132. int MaxFetchServers=DEF_MAX_FETCH_SERVERS; /*+ for fetching. +*/
  133. /*+ The permissions for creation of +*/
  134. mode_t DirPerm=DEF_DIR_PERM;    /*+ directories. +*/
  135. mode_t FilePerm=DEF_FILE_PERM;  /*+ files. +*/
  136. /*+ The name of a progam to run when changing mode to +*/
  137. char *RunOnline=NULL;           /*+ online. +*/
  138. char *RunOffline=NULL;          /*+ offline. +*/
  139. char *RunAutodial=NULL;         /*+ auto dial. +*/
  140. /*+ The entries in the StartUp section. +*/
  141. static Entry startup_entries[]={{"http-port"        ,(void*)&HTTP_Port       ,0,Fixed,PortNumber        },
  142.                                 {"wwwoffle-port"    ,(void*)&WWWOFFLE_Port   ,0,Fixed,PortNumber        },
  143.                                 {"spool-dir"        ,(void*)&SpoolDir        ,0,Fixed,PathName          },
  144.                                 {"run-uid"          ,(void*)&WWWOFFLE_Uid    ,0,Fixed,UserId            },
  145.                                 {"run-gid"          ,(void*)&WWWOFFLE_Gid    ,0,Fixed,GroupId           },
  146.                                 {"use-syslog"       ,(void*)&UseSyslog       ,0,Fixed,Boolean           },
  147.                                 {"password"         ,(void*)&PassWord        ,0,Fixed,String            },
  148.                                 {"max-servers"      ,(void*)&MaxServers      ,0,Fixed,CfgMaxServers     },
  149.                                 {"max-fetch-servers",(void*)&MaxFetchServers ,0,Fixed,CfgMaxFetchServers},
  150.                                 {"dir-perm"         ,(void*)&DirPerm         ,0,Fixed,FileMode          },
  151.                                 {"file-perm"        ,(void*)&FilePerm        ,0,Fixed,FileMode          },
  152.                                 {"run-online"       ,(void*)&RunOnline       ,0,Fixed,PathName          },
  153.                                 {"run-offline"      ,(void*)&RunOffline      ,0,Fixed,PathName          },
  154.                                 {"run-autodial"     ,(void*)&RunAutodial     ,0,Fixed,PathName          },
  155.                                 {NULL               ,NULL                    ,0,-1   ,-1                }};
  156. /*+ The StartUp section. +*/
  157. static Section startup_section={"StartUp",startup_entries};
  158. /* Options Section */
  159. /*+ The level of error logging (see ErrorLevel in errors.h) +*/
  160. int LogLevel=Important,  /*+ in the config file for syslog and stderr. +*/ /* see SetDefaultValues() */
  161.     DebugLevel=-1;       /*+ on the command line for stderr. +*/           /* not in the config file */
  162. /*+ The number of days to display in the index of the latest pages. +*/
  163. int IndexLatestDays; /* see SetDefaultValues() */
  164. /*+ The maximum age of a cached page to use in preference while online. +*/
  165. int RequestChanged; /* see SetDefaultValues() */
  166. /*+ The option to only request changes to a page once per session online. +*/
  167. int RequestChangedOnce; /* see SetDefaultValues() */
  168. /*+ The option to re-request pages that have expired. +*/
  169. int RequestExpired; /* see SetDefaultValues() */
  170. /*+ The option to re-request pages that have the no-cache flag set. +*/
  171. int RequestNoCache; /* see SetDefaultValues() */
  172. /*+ The option to allow or ignore the 'Pragma: no-cache' request. +*/
  173. int PragmaNoCache; /* see SetDefaultValues() */
  174. /*+ The option to not automatically make requests while offline but to need confirmation. +*/
  175. int ConfirmRequests; /* see SetDefaultValues() */
  176. /*+ The amount of time that a socket connection will wait for data. +*/
  177. int SocketTimeout=120; /* see SetDefaultValues() */
  178. /*+ The amount of time that a socket will wait for the intial connection. +*/
  179. int ConnectTimeout=30; /* see SetDefaultValues() */
  180. /*+ The option to retry a failed connection. +*/
  181. int ConnectRetry; /* see SetDefaultValues() */
  182. /*+ The list of allowed SSL port numbers. +*/
  183. static KeyPair **SSLAllowPort; /* see SetDefaultValues() */
  184. /*+ The option to disable the lasttime/prevtime indexs. +*/
  185. int NoLasttimeIndex; /* see SetDefaultValues() */
  186. /*+ The option to keep downloads that are interrupted by the user. +*/
  187. int IntrDownloadKeep; /* see SetDefaultValues() */
  188. /*+ The option to keep on downloading interrupted pages if +*/
  189. int IntrDownloadSize;           /*+ smaller than a given size. +*/ /* see SetDefaultValues() */
  190. int IntrDownloadPercent;        /*+ more than a given percentage complete. +*/ /* see SetDefaultValues() */
  191. /*+ The option to keep downloads that time out. +*/
  192. int TimeoutDownloadKeep; /* see SetDefaultValues() */
  193. /*+ The entries in the Options section. +*/
  194. static Entry options_entries[]={{"log-level"            ,(void*)&LogLevel           ,0,Fixed,CfgLogLevel},
  195.                                 {"index-latest-days"    ,(void*)&IndexLatestDays    ,0,Fixed,AgeDays    },
  196.                                 {"request-changed"      ,(void*)&RequestChanged     ,0,Fixed,TimeSecs   },
  197.                                 {"request-changed-once" ,(void*)&RequestChangedOnce ,0,Fixed,Boolean    },
  198.                                 {"request-expired"      ,(void*)&RequestExpired     ,0,Fixed,Boolean    },
  199.                                 {"request-no-cache"     ,(void*)&RequestNoCache     ,0,Fixed,Boolean    },
  200.                                 {"pragma-no-cache"      ,(void*)&PragmaNoCache      ,0,Fixed,Boolean    },
  201.                                 {"confirm-requests"     ,(void*)&ConfirmRequests    ,0,Fixed,Boolean    },
  202.                                 {"socket-timeout"       ,(void*)&SocketTimeout      ,0,Fixed,TimeSecs   },
  203.                                 {"connect-timeout"      ,(void*)&ConnectTimeout     ,0,Fixed,TimeSecs   },
  204.                                 {"connect-retry"        ,(void*)&ConnectRetry       ,0,Fixed,Boolean    },
  205.                                 {"ssl-allow-port"       ,(void*)&SSLAllowPort       ,1,Fixed,PortNumber },
  206.                                 {"no-lasttime-index"    ,(void*)&NoLasttimeIndex    ,0,Fixed,Boolean    },
  207.                                 {"intr-download-keep"   ,(void*)&IntrDownloadKeep   ,0,Fixed,Boolean    },
  208.                                 {"intr-download-size"   ,(void*)&IntrDownloadSize   ,0,Fixed,FileSize   },
  209.                                 {"intr-download-percent",(void*)&IntrDownloadPercent,0,Fixed,Percentage },
  210.                                 {"timeout-download-keep",(void*)&TimeoutDownloadKeep,0,Fixed,Boolean    },
  211.                                 {NULL                   ,NULL                       ,0,-1   ,-1         }};
  212. /*+ The Options section. +*/
  213. static Section options_section={"Options",options_entries};
  214. /* FetchOptions section */
  215. /*+ The option to also fetch style sheets. +*/
  216. int FetchStyleSheets; /* see SetDefaultValues() */
  217. /*+ The option to also fetch images. +*/
  218. int FetchImages; /* see SetDefaultValues() */
  219. /*+ The option to also fetch frames. +*/
  220. int FetchFrames; /* see SetDefaultValues() */
  221. /*+ The option to also fetch scripts. +*/
  222. int FetchScripts; /* see SetDefaultValues() */
  223. /*+ The option to also fetch objects. +*/
  224. int FetchObjects; /* see SetDefaultValues() */
  225. /*+ The entries in the FetchOptions section. +*/
  226. static Entry fetchoptions_entries[]={{"stylesheets",(void*)&FetchStyleSheets,0,Fixed,Boolean},
  227.                                      {"images"     ,(void*)&FetchImages     ,0,Fixed,Boolean},
  228.                                      {"frames"     ,(void*)&FetchFrames     ,0,Fixed,Boolean},
  229.                                      {"scripts"    ,(void*)&FetchScripts    ,0,Fixed,Boolean},
  230.                                      {"objects"    ,(void*)&FetchObjects    ,0,Fixed,Boolean},
  231.                                      {NULL         ,NULL                    ,0,-1   ,-1     }};
  232. /*+ The FetchOptions section. +*/
  233. static Section fetchoptions_section={"FetchOptions",fetchoptions_entries};
  234. /* ModifyHTML section */
  235. /*+ The option to turn on the modifications in this section. +*/
  236. int EnableHTMLModifications; /* see SetDefaultValues() */
  237. /*+ The option of a tag that can be added to the bottom of the spooled pages with the date and some buttons. +*/
  238. int AddCacheInfo; /* see SetDefaultValues() */
  239. /*+ The options to modify the anchor tags in the HTML. +*/
  240. char *AnchorModifyBegin[3], /* see SetDefaultValues() */
  241.      *AnchorModifyEnd[3];   /* see SetDefaultValues() */
  242. /*+ The option to disable scripts and scripted actions. +*/
  243. int DisableHTMLScript; /* see SetDefaultValues() */
  244. /*+ The option to disable the <blink> tag. +*/
  245. int DisableHTMLBlink; /* see SetDefaultValues() */
  246. /*+ The option to disable animated GIFs. +*/
  247. int DisableAnimatedGIF; /* see SetDefaultValues() */
  248. /*+ The entries in the ModifyHTMLOptions section. +*/
  249. static Entry modifyhtml_entries[]={{"enable-modify-html"     ,(void*)&EnableHTMLModifications,0,Fixed,Boolean},
  250.                                    {"add-cache-info"         ,(void*)&AddCacheInfo           ,0,Fixed,Boolean},
  251.                                    {"anchor-cached-begin"    ,(void*)&AnchorModifyBegin[0]   ,0,Fixed,String },
  252.                                    {"anchor-cached-end"      ,(void*)&AnchorModifyEnd[0]     ,0,Fixed,String },
  253.                                    {"anchor-requested-begin" ,(void*)&AnchorModifyBegin[1]   ,0,Fixed,String },
  254.                                    {"anchor-requested-end"   ,(void*)&AnchorModifyEnd[1]     ,0,Fixed,String },
  255.                                    {"anchor-not-cached-begin",(void*)&AnchorModifyBegin[2]   ,0,Fixed,String },
  256.                                    {"anchor-not-cached-end"  ,(void*)&AnchorModifyEnd[2]     ,0,Fixed,String },
  257.                                    {"disable-script"         ,(void*)&DisableHTMLScript      ,0,Fixed,Boolean},
  258.                                    {"disable-blink"          ,(void*)&DisableHTMLBlink       ,0,Fixed,Boolean},
  259.                                    {"disable-animated-gif"   ,(void*)&DisableAnimatedGIF     ,0,Fixed,Boolean},
  260.                                    {NULL                     ,NULL                           ,0,-1   ,-1     }};
  261. /*+ The ModifyHTML section. +*/
  262. static Section modifyhtml_section={"ModifyHTML",modifyhtml_entries};
  263. /* LocalHost section */
  264. /*+ The list of localhost hostnames. +*/
  265. static KeyPair **LocalHost; /* see SetDefaultValues() */
  266. /*+ The entries in the LocalHost section. +*/
  267. static Entry localhost_entries[]={{""  ,(void*)&LocalHost,1,Host,None},
  268.                                   {NULL,NULL             ,0,-1  ,-1  }};
  269. /*+ The LocalHost section. +*/
  270. static Section localhost_section={"LocalHost",localhost_entries};
  271. /* LocalNet section */
  272. /*+ The list of local network hostnames. +*/
  273. static KeyPair **LocalNet; /* see SetDefaultValues() */
  274. /*+ The entries in the LocalNet section. +*/
  275. static Entry localnet_entries[]={{""  ,(void*)&LocalNet,1,Host,None},
  276.                                  {NULL,NULL            ,0,-1  ,-1  }};
  277. /*+ The LocalNet section. +*/
  278. static Section localnet_section={"LocalNet",localnet_entries};
  279. /* AllowedConnectHosts section */
  280. /*+ The list of allowed hostnames. +*/
  281. static KeyPair **AllowedConnectHosts; /* see SetDefaultValues() */
  282. /*+ The entries in the AllowedConnectHosts section. +*/
  283. static Entry allowedconnecthosts_entries[]={{""  ,(void*)&AllowedConnectHosts,1,Host,None},
  284.                                             {NULL,NULL                       ,0,-1  ,-1  }};
  285. /*+ The AllowedConnectHosts section. +*/
  286. static Section allowedconnecthosts_section={"AllowedConnectHosts",allowedconnecthosts_entries};
  287. /* AllowedConnectUsers section */
  288. /*+ The list of allowed usernames and paswords. +*/
  289. static KeyPair **AllowedConnectUsers; /* see SetDefaultValues() */
  290. /*+ The entries in the AllowedConnectUsers section. +*/
  291. static Entry allowedconnectusers_entries[]={{""  ,(void*)&AllowedConnectUsers,1,UserPass,None},
  292.                                             {NULL,NULL                       ,0,-1      ,-1  }};
  293. /*+ The AllowedConnectUsers section. +*/
  294. static Section allowedconnectusers_section={"AllowedConnectUsers",allowedconnectusers_entries};
  295. /* DontCache section */
  296. /*+ The list of URLs not to cache. +*/
  297. static KeyPair **DontCache; /* see SetDefaultValues() */
  298. /*+ The entries in the DontCache section. +*/
  299. static Entry dontcache_entries[]={{""  ,(void*)&DontCache,1,UrlSpecification,None},
  300.                                   {NULL,NULL             ,0,-1              ,-1  }};
  301. /*+ The DontCache section. +*/
  302. static Section dontcache_section={"DontCache",dontcache_entries};
  303. /* DontGet section */
  304. /*+ The list of URLs not to get. +*/
  305. static KeyPair **DontGet; /* see SetDefaultValues() */
  306. /*+ The replacement URL. +*/
  307. char *DontGetReplacementURL; /* see SetDefaultValues() */
  308. /*+ The entries in the DontGet section. +*/
  309. static Entry dontget_entries[]={{"replacement",(void*)&DontGetReplacementURL,0,Fixed           ,Url        },
  310.                                 {""           ,(void*)&DontGet              ,1,UrlSpecification,OptionalUrl},
  311.                                 {NULL         ,NULL                         ,0,-1              ,-1         }};
  312. /*+ The DontGet section. +*/
  313. static Section dontget_section={"DontGet",dontget_entries};
  314. /* DontGetRecursive section */
  315. /*+ The list of URLs not to get. +*/
  316. static KeyPair **DontGetRecursive; /* see SetDefaultValues() */
  317. /*+ The entries in the DontGetRecursive section. +*/
  318. static Entry dontgetrecursive_entries[]={{""  ,(void*)&DontGetRecursive,1,UrlSpecification,None},
  319.                                          {NULL,NULL                    ,0,-1              ,-1  }};
  320. /*+ The DontGetRecursive section. +*/
  321. static Section dontgetrecursive_section={"DontGetRecursive",dontgetrecursive_entries};
  322. /* DontRequestOffline section */
  323. /*+ The list of URLs not to request. +*/
  324. static KeyPair **DontRequestOffline; /* see SetDefaultValues() */
  325. /*+ The entries in the DontRequestOffline section. +*/
  326. static Entry dontrequestoffline_entries[]={{""  ,(void*)&DontRequestOffline,1,UrlSpecification,None},
  327.                                            {NULL,NULL                      ,0,-1              ,-1  }};
  328. /*+ The DontRequestOffline section. +*/
  329. static Section dontrequestoffline_section={"DontRequestOffline",dontrequestoffline_entries};
  330. /* CensorHeader section */
  331. /*+ The list of censored headers. +*/
  332. static KeyPair **CensorHeader; /* see SetDefaultValues() */
  333. /*+ Flags to cause the referer header to be mangled. +*/
  334. static int RefererSelf, /* see SetDefaultValues() */
  335.            RefererSelfDir; /* see SetDefaultValues() */
  336. /*+ The entries in the censor headers section. +*/
  337. static Entry censorheader_entries[]={{"referer-self"    ,(void*)&RefererSelf   ,0,Fixed ,Boolean},
  338.                                      {"referer-self-dir",(void*)&RefererSelfDir,0,Fixed ,Boolean},
  339.                                      {""                ,(void*)&CensorHeader  ,1,String,String },
  340.                                      {NULL              ,NULL                  ,0,-1    ,-1     }};
  341. /*+ The CensorHeader section. +*/
  342. static Section censorheader_section={"CensorHeader",censorheader_entries};
  343. /* FTPOptions section */
  344. /*+ The anon-ftp username. +*/
  345. static char *FTPUserName; /* see SetDefaultValues() */
  346. /*+ The anon-ftp password. +*/
  347. static char *FTPPassWord; /* see SetDefaultValues() */
  348. /*+ The information that is needed to allow non-anonymous access, +*/
  349. static KeyPair **FTPAuthHost, /*+ hostname +*/ /* see SetDefaultValues() */
  350.                **FTPAuthUser, /*+ username +*/ /* see SetDefaultValues() */
  351.                **FTPAuthPass; /*+ password +*/ /* see SetDefaultValues() */
  352. /*+ The entries in the FTPOptions section. +*/
  353. static Entry ftpoptions_entries[]={{"anon-username",(void*)&FTPUserName,0,Fixed,String     },
  354.                                    {"anon-password",(void*)&FTPPassWord,0,Fixed,String     },
  355.                                    {"auth-hostname",(void*)&FTPAuthHost,1,Fixed,HostAndPort},
  356.                                    {"auth-username",(void*)&FTPAuthUser,1,Fixed,String     },
  357.                                    {"auth-password",(void*)&FTPAuthPass,1,Fixed,String     },
  358.                                    {NULL           ,NULL               ,0,-1   ,-1         }};
  359. /*+ The FTPOptions section. +*/
  360. static Section ftpoptions_section={"FTPOptions",ftpoptions_entries};
  361. /* MIMETypes section */
  362. /*+ The default MIME type. +*/
  363. static char *DefaultMIMEType; /* see SetDefaultValues() */
  364. /*+ The list of MIME types. +*/
  365. static KeyPair **MIMETypes; /* see SetDefaultValues() */
  366. /*+ The entries in the FTPOptions section. +*/
  367. static Entry mimetypes_entries[]={{"default",(void*)&DefaultMIMEType,0,Fixed  ,MIMEType},
  368.                                   {""       ,(void*)&MIMETypes      ,1,FileExt,MIMEType},
  369.                                   {NULL     ,NULL                   ,0,-1     ,-1      }};
  370. /*+ The MIMETypes section. +*/
  371. static Section mimetypes_section={"MIMETypes",mimetypes_entries};
  372. /* Proxy section */
  373. /*+ The list of hostnames and proxies. +*/
  374. static KeyPair **Proxies; /* see SetDefaultValues() */
  375. /*+ The information that is needed to allow authorisation headers to be added, +*/
  376. static KeyPair **ProxyAuthHost, /*+ hostname +*/ /* see SetDefaultValues() */
  377.                **ProxyAuthUser, /*+ username +*/ /* see SetDefaultValues() */
  378.                **ProxyAuthPass; /*+ password +*/ /* see SetDefaultValues() */
  379. /*+ The SSL proxy to use. +*/
  380. char *SSLProxy; /* see SetDefaultValues() */
  381. /*+ The entries in the Proxy section. +*/
  382. static Entry proxy_entries[]={{"auth-hostname",(void*)&ProxyAuthHost,1,Fixed           ,HostAndPort      },
  383.                               {"auth-username",(void*)&ProxyAuthUser,1,Fixed           ,String           },
  384.                               {"auth-password",(void*)&ProxyAuthPass,1,Fixed           ,String           },
  385.                               {"ssl"          ,(void*)&SSLProxy     ,0,Fixed           ,HostAndPortOrNone},
  386.                               {""             ,(void*)&Proxies      ,1,UrlSpecification,HostAndPortOrNone},
  387.                               {NULL           ,NULL                 ,0,-1              ,-1               }};
  388. /*+ The Proxy section. +*/
  389. static Section proxy_section={"Proxy",proxy_entries};
  390. /* DontIndex section */
  391. /*+ The list of URLs not to index in the outgoing index. +*/
  392. static KeyPair **DontIndexOutgoing; /* see SetDefaultValues() */
  393. /*+ The list of URLs not to index in the latest/lastime/prevtime indexes. +*/
  394. static KeyPair **DontIndexLatest; /* see SetDefaultValues() */
  395. /*+ The list of URLs not to index in the monitor index. +*/
  396. static KeyPair **DontIndexMonitor; /* see SetDefaultValues() */
  397. /*+ The list of URLs not to index in the host indexes. +*/
  398. static KeyPair **DontIndexHost; /* see SetDefaultValues() */
  399. /*+ The list of URLs not to index. +*/
  400. static KeyPair **DontIndex; /* see SetDefaultValues() */
  401. /*+ The entries in the DontIndex section. +*/
  402. static Entry dontindex_entries[]={{"outgoing" ,(void*)&DontIndexOutgoing,1,Fixed           ,UrlSpecification},
  403.                                   {"latest"   ,(void*)&DontIndexLatest  ,1,Fixed           ,UrlSpecification},
  404.                                   {"monitor"  ,(void*)&DontIndexMonitor ,1,Fixed           ,UrlSpecification},
  405.                                   {"host"     ,(void*)&DontIndexHost    ,1,Fixed           ,UrlSpecification},
  406.                                   {""         ,(void*)&DontIndex        ,1,UrlSpecification,None            },
  407.                                   {NULL       ,NULL                     ,0,-1              ,-1              }};
  408. /*+ The DontIndex section. +*/
  409. static Section dontindex_section={"DontIndex",dontindex_entries};
  410. /* Alias section */
  411. /*+ The list of protocols/hostnames and their aliases. +*/
  412. static KeyPair **Aliases; /* see SetDefaultValues() */
  413. /*+ The entries in the Alias section. +*/
  414. static Entry alias_entries[]={{""  ,(void*)&Aliases,1,UrlSpecification,UrlSpecification},
  415.                               {NULL,NULL           ,0,-1              ,-1              }};
  416. /*+ The Alias section. +*/
  417. static Section alias_section={"Alias",alias_entries};
  418. /* Purge section */
  419. /*+ A flag to indicate that the modification time is used instead of the access time. +*/
  420. int PurgeUseMTime; /* see SetDefaultValues() */
  421. /*+ The default age for purging files. +*/
  422. int DefaultPurgeAge; /* see SetDefaultValues() */
  423. /*+ The maximum allowed size of the cache. +*/
  424. int PurgeCacheSize; /* see SetDefaultValues() */
  425. /*+ The minimum allowed free disk space. +*/
  426. int PurgeDiskFree; /* see SetDefaultValues() */
  427. /*+ A flag to indicate it the whole URL is used to choose the purge age. +*/
  428. int PurgeUseURL; /* see SetDefaultValues() */
  429. /*+ A flag to indicate if the DontGet hosts are to be purged. +*/
  430. static int PurgeDontGet; /* see SetDefaultValues() */
  431. /*+ A flag to indicate if the DontCache hosts are to be purged. +*/
  432. static int PurgeDontCache; /* see SetDefaultValues() */
  433. /*+ The list of hostnames and purge ages. +*/
  434. static KeyPair **PurgeAges; /* see SetDefaultValues() */
  435. /*+ The entries in the Purge section. +*/
  436. static Entry purge_entries[]={{"use-mtime"     ,(void*)&PurgeUseMTime  ,0,Fixed           ,Boolean  },
  437.                               {"default"       ,(void*)&DefaultPurgeAge,0,Fixed           ,AgeDays  },
  438.                               {"max-size"      ,(void*)&PurgeCacheSize ,0,Fixed           ,CacheSize},
  439.                               {"min-free"      ,(void*)&PurgeDiskFree  ,0,Fixed           ,CacheSize},
  440.                               {"use-url"       ,(void*)&PurgeUseURL    ,0,Fixed           ,Boolean  },
  441.                               {"del-dontget"   ,(void*)&PurgeDontGet   ,0,Fixed           ,Boolean  },
  442.                               {"del-dontcache" ,(void*)&PurgeDontCache ,0,Fixed           ,Boolean  },
  443.                               {""              ,(void*)&PurgeAges      ,1,UrlSpecification,AgeDays  },
  444.                               {NULL            ,NULL                   ,0,-1              ,-1       }};
  445. /*+ The Purge section. +*/
  446. static Section purge_section={"Purge",purge_entries};
  447. /* All sections */
  448. /*+ The list of sections (NULL terminated). +*/
  449. static Section *sections[]={&startup_section,
  450.                             &options_section,
  451.                             &fetchoptions_section,
  452.                             &modifyhtml_section,
  453.                             &localhost_section,
  454.                             &localnet_section,
  455.                             &allowedconnecthosts_section,
  456.                             &allowedconnectusers_section,
  457.                             &dontcache_section,
  458.                             &dontget_section,
  459.                             &dontgetrecursive_section,
  460.                             &dontrequestoffline_section,
  461.                             &censorheader_section,
  462.                             &ftpoptions_section,
  463.                             &mimetypes_section,
  464.                             &proxy_section,
  465.                             &dontindex_section,
  466.                             &alias_section,
  467.                             &purge_section,
  468.                             NULL};
  469. /* Local functions */
  470. static int match_url_specification(UrlSpec *spec,char *proto,char *host,char *path,char *args);
  471. static int wildcard_match(char *string,char *pattern);
  472. static char *DefaultFTPPassWord(void);
  473. static KeyPair **DefaultAliasLinks(void);
  474. static void ReadFile(FILE *config);
  475. static void ReadSection(FILE *config,Section *section);
  476. static char* ReadLine(FILE *config);
  477. static int ParseEntry(Entry *entry,char *left,char *right);
  478. static int ParseValue(char *text,ConfigType type,void *pointer,int rhs);
  479. static int isanumber(const char *string);
  480. static void SetDefaultValues(void);
  481. static void SaveOldValues(void);
  482. static void RestoreOldValues(void);
  483. static void RemoveOldValues(void);
  484. static void FreeKeyPairList(KeyPair **list,int freewhat);
  485. #define FREE_KEY_STRING    1
  486. #define FREE_KEY_URLSPEC   2
  487. #define FREE_VALUE_STRING  4
  488. #define FREE_VALUE_URLSPEC 8
  489. /*+ Only the first time that the config file is read can the StartUp section be used. +*/
  490. static int first_time=1;
  491. /*+ The error message. +*/
  492. static char *errmsg;
  493. /*+ The line number in the configuration file. +*/
  494. static int line_no;
  495. /*+ The name of the configuration file. +*/
  496. char *file_name;
  497. /*++++++++++++++++++++++++++++++++++++++
  498.   Read in the configuration file.
  499.   int fd The file descriptor to write the error message to.
  500.   ++++++++++++++++++++++++++++++++++++++*/
  501. int ReadConfigFile(int fd)
  502. {
  503.  FILE* config;
  504.  if(first_time)
  505.     SetDefaultValues();
  506.  errmsg=NULL;
  507.  if(*ConfigFile!='/')
  508.    {
  509.     static char cwd[PATH_MAX+1];
  510.     if(getcwd(cwd,PATH_MAX))
  511.       {
  512.        strcat(cwd,"/");
  513.        strcat(cwd,ConfigFile);
  514.        ConfigFile=cwd;
  515.       }
  516.    }
  517.  config=fopen(ConfigFile,"r");
  518.  if(!config)
  519.    {
  520.     write_formatted(fd,"Cannot open the configuration file '%s'n",ConfigFile);
  521.     return(1);
  522.    }
  523.  SaveOldValues();
  524.  SetDefaultValues();
  525.  ReadFile(config);
  526.  if(errmsg)
  527.     RestoreOldValues();
  528.  else
  529.     RemoveOldValues();
  530.  fclose(config);
  531.  if(errmsg)
  532.    {
  533.     write_formatted(fd,"Syntax error at line %d in '%s'; %sn",line_no,file_name,errmsg);
  534.     free(errmsg);
  535.    }
  536.  if(first_time)
  537.     first_time=0;
  538.  if(errmsg)
  539.     return(1);
  540.  else
  541.     return(0);
  542. }
  543. /*++++++++++++++++++++++++++++++++++++++
  544.   Decide if the specified host and port number is allowed for SSL.
  545.   int IsSSLAllowedPort Returns true if it is allowed.
  546.   char *host The hostname and port number to check.
  547.   ++++++++++++++++++++++++++++++++++++++*/
  548. int IsSSLAllowedPort(char *host)
  549. {
  550.  KeyPair **p;
  551.  char *colon=strchr(host,':');
  552.  int port,isit=0;
  553.  if(!colon)
  554.     return(0);
  555.  port=atoi(colon+1);
  556.  if(SSLAllowPort)
  557.     for(p=SSLAllowPort;(*p)!=&KeyPairEnd;p++)
  558.        if((*p)->value.integer==port)
  559.          {isit=1;break;}
  560.  return(isit);
  561. }
  562. /*++++++++++++++++++++++++++++++++++++++
  563.   Get the first specified name of the server host.
  564.   char *GetLocalHost Returns the first named localhost.
  565.   int port If true then return the port as well.
  566.   ++++++++++++++++++++++++++++++++++++++*/
  567. char *GetLocalHost(int port)
  568. {
  569.  char *localhost,*ret;
  570.  if(LocalHost)
  571.     localhost=(*LocalHost)->key.string;
  572.  else
  573.     localhost="localhost";
  574.  ret=(char*)malloc(strlen(localhost)+8);
  575.  if(port)
  576.     sprintf(ret,"%s:%d",localhost,HTTP_Port);
  577.  else
  578.     strcpy(ret,localhost);
  579.  return(ret);
  580. }
  581. #if !defined(SETUP_ONLY)
  582. /*++++++++++++++++++++++++++++++++++++++
  583.   Check if the specified hostname is the localhost.
  584.   int IsLocalHost Return true if the host is the local host.
  585.   char *host The name of the host (and port number) to be checked.
  586.   int port If true then check the port number as well.
  587.   ++++++++++++++++++++++++++++++++++++++*/
  588. int IsLocalHost(char *host,int port)
  589. {
  590.  KeyPair **p;
  591.  char *colon=strchr(host,':');
  592.  int isit=0;
  593.  if(colon)
  594.     *colon=0;
  595.  if(LocalHost)
  596.     for(p=LocalHost;(*p)!=&KeyPairEnd;p++)
  597.        if(!strcmp((*p)->key.string,host))
  598.          {isit=1;break;}
  599.  if(colon)
  600.     *colon=':';
  601.  if(isit && port)
  602.    {
  603.     if((colon && atoi(colon+1)==HTTP_Port) ||
  604.        (!colon && HTTP_Port==80))
  605.        ;
  606.     else
  607.        isit=0;
  608.    }
  609.  return(isit);
  610. }
  611. /*++++++++++++++++++++++++++++++++++++++
  612.   Check if the specified hostname is in the local network.
  613.   int IsLocalNetHost Return true if the host is on the local network.
  614.   char *host The name of the host (and port number) to be checked.
  615.   ++++++++++++++++++++++++++++++++++++++*/
  616. int IsLocalNetHost(char *host)
  617. {
  618.  KeyPair **p;
  619.  char *colon=strchr(host,':');
  620.  int isit=0;
  621.  if(colon)
  622.     *colon=0;
  623.  if(IsLocalHost(host,0))
  624.     isit=1;
  625.  if(LocalNet && !isit)
  626.     for(p=LocalNet;(*p)!=&KeyPairEnd;p++)
  627.        if(*(*p)->key.string=='!')
  628.          {
  629.           if(wildcard_match(host,(*p)->key.string+1))
  630.             {isit=0;break;}
  631.          }
  632.        else if(wildcard_match(host,(*p)->key.string))
  633.          {isit=1;break;}
  634.  if(colon)
  635.     *colon=':';
  636.  return(isit);
  637. }
  638. /*++++++++++++++++++++++++++++++++++++++
  639.   Check if the specified hostname is allowed to connect.
  640.   int IsAllowedConnectHost Return true if it is allowed to connect.
  641.   char *host The name of the host to be checked.
  642.   ++++++++++++++++++++++++++++++++++++++*/
  643. int IsAllowedConnectHost(char *host)
  644. {
  645.  KeyPair **p;
  646.  int isit=0;
  647.  if(LocalHost)
  648.     for(p=LocalHost;(*p)!=&KeyPairEnd;p++)
  649.        if(!strcmp((*p)->key.string,host))
  650.          {isit=1;break;}
  651.  if(AllowedConnectHosts && !isit)
  652.     for(p=AllowedConnectHosts;(*p)!=&KeyPairEnd;p++)
  653.        if(*(*p)->key.string=='!')
  654.          {
  655.           if(wildcard_match(host,(*p)->key.string+1))
  656.             {isit=0;break;}
  657.          }
  658.        else if(wildcard_match(host,(*p)->key.string))
  659.          {isit=1;break;}
  660.  return(isit);
  661. }
  662. /*++++++++++++++++++++++++++++++++++++++
  663.   Check if the specified username and password is allowed to connect.
  664.   char *IsAllowedConnectUser Return the username if it is allowed to connect.
  665.   char *userpass The encoded username and password of the user to be checked.
  666.   ++++++++++++++++++++++++++++++++++++++*/
  667. char *IsAllowedConnectUser(char *userpass)
  668. {
  669.  KeyPair **p;
  670.  char *isit;
  671.  if(AllowedConnectUsers)
  672.     isit=NULL;
  673.  else
  674.     isit="anybody";
  675.  if(AllowedConnectUsers && userpass)
  676.    {
  677.     char *up=userpass;
  678.     while(*up!=' ') up++;
  679.     while(*up==' ') up++;
  680.     for(p=AllowedConnectUsers;(*p)!=&KeyPairEnd;p++)
  681.        if(!strcmp((*p)->key.string,up))
  682.          {
  683.           char *colon;
  684.           int l;
  685.           isit=Base64Decode((*p)->key.string,&l);
  686.           colon=strchr(isit,':');
  687.           *colon=0;
  688.           break;
  689.          }
  690.    }
  691.  return(isit);
  692. }
  693. /*++++++++++++++++++++++++++++++++++++++
  694.   Check if the specified URL is to be cached.
  695.   int IsNotCached Return true if it is not to be cached.
  696.   char *proto The name of the protocol to check.
  697.   char *host The name of the host to check.
  698.   char *path The pathname of the URL to check.
  699.   char *args The arguments of the URL to check.
  700.   ++++++++++++++++++++++++++++++++++++++*/
  701. int IsNotCached(char *proto,char *host,char *path,char *args)
  702. {
  703.  KeyPair **p;
  704.  if(DontCache)
  705.     for(p=DontCache;(*p)!=&KeyPairEnd;p++)
  706.       {
  707.        int match=match_url_specification((*p)->key.urlspec,proto,host,path,args);
  708.        if(match)
  709.           return(!(*p)->key.urlspec->negated);
  710.       }
  711.  return(0);
  712. }
  713. /*++++++++++++++++++++++++++++++++++++++
  714.   Check if the specified URL is to be got.
  715.   int IsNotGot Return true if it is not to be got.
  716.   char *proto The name of the protocol to check.
  717.   char *host The name of the host to check.
  718.   char *path The pathname of the URL to check.
  719.   char *args The arguments of the URL to check.
  720.   ++++++++++++++++++++++++++++++++++++++*/
  721. int IsNotGot(char *proto,char *host,char *path,char *args)
  722. {
  723.  KeyPair **p;
  724.  if(DontGet)
  725.     for(p=DontGet;(*p)!=&KeyPairEnd;p++)
  726.       {
  727.        int match=match_url_specification((*p)->key.urlspec,proto,host,path,args);
  728.        if(match)
  729.           return(!(*p)->key.urlspec->negated);
  730.       }
  731.  return(0);
  732. }
  733. /*++++++++++++++++++++++++++++++++++++++
  734.   Get the replacement URL for an URL that is not to be got.
  735.   int NotGotReplacement Returns the URL if a specific one is specified or the default one.
  736.   char *proto The name of the protocol to check.
  737.   char *host The name of the host to check.
  738.   char *path The pathname of the URL to check.
  739.   char *args The arguments of the URL to check.
  740.   ++++++++++++++++++++++++++++++++++++++*/
  741. char *NotGotReplacement(char *proto,char *host,char *path,char *args)
  742. {
  743.  KeyPair **p;
  744.  if(DontGet)
  745.     for(p=DontGet;(*p)!=&KeyPairEnd;p++)
  746.       {
  747.        int match=match_url_specification((*p)->key.urlspec,proto,host,path,args);
  748.        if(match && !(*p)->key.urlspec->negated && (*p)->value.string)
  749.           return((*p)->value.string);
  750.       }
  751.  return(DontGetReplacementURL);
  752. }
  753.  
  754. /*++++++++++++++++++++++++++++++++++++++
  755.   Check if the specified URL is to be got recursively.
  756.   int IsNotGotRecursive Return true if it is not to be got recursively.
  757.   char *proto The name of the protocol to check.
  758.   char *host The name of the host to check.
  759.   char *path The pathname of the URL to check.
  760.   char *args The arguments of the URL to check.
  761.   ++++++++++++++++++++++++++++++++++++++*/
  762. int IsNotGotRecursive(char *proto,char *host,char *path,char *args)
  763. {
  764.  KeyPair **p;
  765.  if(DontGetRecursive)
  766.     for(p=DontGetRecursive;(*p)!=&KeyPairEnd;p++)
  767.       {
  768.        int match=match_url_specification((*p)->key.urlspec,proto,host,path,args);
  769.        if(match)
  770.           return(!(*p)->key.urlspec->negated);
  771.       }
  772.  return(0);
  773. }
  774. /*++++++++++++++++++++++++++++++++++++++
  775.   Check if the specified URL is to be requested while offline.
  776.   int IsNotRequestedOffline Return true if it is not to be requested.
  777.   char *proto The name of the protocol to check.
  778.   char *host The name of the host to check.
  779.   char *path The pathname of the URL to check.
  780.   char *args The arguments of the URL to check.
  781.   ++++++++++++++++++++++++++++++++++++++*/
  782. int IsNotRequestedOffline(char *proto,char *host,char *path,char *args)
  783. {
  784.  KeyPair **p;
  785.  if(DontRequestOffline)
  786.     for(p=DontRequestOffline;(*p)!=&KeyPairEnd;p++)
  787.       {
  788.        int match=match_url_specification((*p)->key.urlspec,proto,host,path,args);
  789.        if(match)
  790.           return(!(*p)->key.urlspec->negated);
  791.       }
  792.  return(0);
  793. }
  794. /*++++++++++++++++++++++++++++++++++++++
  795.   Decide if the header line is to be sent to the server/browser.
  796.   char *CensoredHeader Returns the value to be inserted or NULL if it is to be removed.
  797.   char *url the URL that is being requested, or NULL for a reply.
  798.   char *key The key to check.
  799.   char *val The default value to use.
  800.   ++++++++++++++++++++++++++++++++++++++*/
  801. char *CensoredHeader(char *url,char *key,char *val)
  802. {
  803.  KeyPair **p;
  804.  char *new=val;
  805.  if(CensorHeader)
  806.     for(p=CensorHeader;(*p)!=&KeyPairEnd;p++)
  807.        if(!strcmp((*p)->key.string,key))
  808.          {
  809.           if(!(*p)->value.string)
  810.              new=NULL;
  811.           else if(strcmp((*p)->value.string,val))
  812.             {
  813.              new=(char*)malloc(strlen((*p)->value.string)+1);
  814.              strcpy(new,(*p)->value.string);
  815.             }
  816.           break;
  817.          }
  818.  if(url && new && (RefererSelf || RefererSelfDir) && !strcmp("Referer",key))
  819.    {
  820.     new=(char*)malloc(strlen(url)+1);
  821.     strcpy(new,url);
  822.     if(RefererSelfDir)
  823.       {
  824.        char *p=new+strlen(new)-1,*ques=strchr(new,'?');
  825.        if(ques)
  826.           p=ques;
  827.        while(*p!='/')
  828.           *p--=0;
  829.       }
  830.    }
  831.  return(new);
  832. }
  833. /*++++++++++++++++++++++++++++++++++++++
  834.   Determine an email address to use as the FTP password.
  835.   char *DefaultFTPPassword Returns a best-guess password.
  836.   ++++++++++++++++++++++++++++++++++++++*/
  837. static char *DefaultFTPPassWord(void)
  838. {
  839.  struct passwd *pwd;
  840.  char *username,*fqdn,*password;
  841.  pwd=getpwuid(getuid());
  842.  if(!pwd)
  843.     username="root";
  844.  else
  845.     username=pwd->pw_name;
  846.  fqdn=GetFQDN();
  847.  if(!fqdn)
  848.     fqdn="";
  849.  password=(char*)malloc(strlen(username)+strlen(fqdn)+4);
  850.  sprintf(password,"%s@%s",username,fqdn);
  851.  return(password);
  852. }
  853. /*++++++++++++++++++++++++++++++++++++++
  854.   Determine what username and password to use for the FTP server.
  855.   int WhatFTPUserPass Return 1 if there is a non-default one.
  856.   char *host The FTP server.
  857.   char **user Returns the username.
  858.   char **pass Returns the password.
  859.   ++++++++++++++++++++++++++++++++++++++*/
  860. int WhatFTPUserPass(char *host,char **user,char **pass)
  861. {
  862.  int def=0;
  863.  KeyPair **h,**u,**p;
  864.  *user=FTPUserName;
  865.  *pass=FTPPassWord;
  866.  if(FTPAuthHost && FTPAuthUser && FTPAuthPass)
  867.     for(h=FTPAuthHost,u=FTPAuthUser,p=FTPAuthPass;(*h)!=&KeyPairEnd && (*u)!=&KeyPairEnd && (*p)!=&KeyPairEnd;h++,u++,p++)
  868.       {
  869.        if(!strcmp(host,(*h)->value.string))
  870.          {
  871.           *user=(*u)->value.string;
  872.           *pass=(*p)->value.string;
  873.           def=1;
  874.           break;
  875.          }
  876.       }
  877.  return(def); 
  878. }
  879. /*++++++++++++++++++++++++++++++++++++++
  880.   Decide what mime type to apply for a given file.
  881.   char *WhatMIMEType Returns the MIME Type.
  882.   char *path The path of the file.
  883.   ++++++++++++++++++++++++++++++++++++++*/
  884. char *WhatMIMEType(char *path)
  885. {
  886.  char *mimetype=DefaultMIMEType;
  887.  int maxlen=0;
  888.  KeyPair **m;
  889.  if(MIMETypes)
  890.     for(m=MIMETypes;(*m)!=&KeyPairEnd;m++)
  891.        if(strlen(path)>strlen((*m)->key.string) &&
  892.           strlen((*m)->key.string)>maxlen &&
  893.           !strcmp((*m)->key.string,path+strlen(path)-strlen((*m)->key.string)))
  894.          {mimetype=(*m)->value.string;maxlen=strlen((*m)->value.string);}
  895.  return(mimetype);
  896. }
  897. /*++++++++++++++++++++++++++++++++++++++
  898.   Determine the proxy to use for a specified host.
  899.   char *WhichProxy Return a pointer to the proxy.
  900.   char *proto The name of the protocol used.
  901.   char *host The name of the host to be contacted.
  902.   ++++++++++++++++++++++++++++++++++++++*/
  903. char *WhichProxy(char *proto,char *host)
  904. {
  905.  KeyPair **p;
  906.  char *proxy=NULL;
  907.  int matchlen=0,ml;
  908.  if(Proxies)
  909.     for(p=Proxies;(*p)!=&KeyPairEnd;p++)
  910.        if((ml=match_url_specification((*p)->key.urlspec,proto,host,"/",NULL)))
  911.           if(ml>matchlen)
  912.             {
  913.              matchlen=ml;
  914.              proxy=(*p)->value.string;
  915.             }
  916.  return(proxy);
  917. }
  918. /*++++++++++++++++++++++++++++++++++++++
  919.   Determine what authentication password is required for the proxy.
  920.   char *WhatProxyAuth Returns the password:username combination.
  921.   char *proxy The name of the proxy.
  922.   ++++++++++++++++++++++++++++++++++++++*/
  923. char *WhatProxyAuth(char *proxy)
  924. {
  925.  KeyPair **h,**u,**p;
  926.  char *user=NULL,*pass=NULL;
  927.  char *userpass=NULL;
  928.  if(ProxyAuthHost && ProxyAuthUser && ProxyAuthPass)
  929.    {
  930.     for(h=ProxyAuthHost,u=ProxyAuthUser,p=ProxyAuthPass;(*h)!=&KeyPairEnd && (*u)!=&KeyPairEnd && (*p)!=&KeyPairEnd;h++,u++,p++)
  931.       {
  932.        if(!strcmp(proxy,(*h)->value.string))
  933.          {
  934.           user=(*u)->value.string;
  935.           pass=(*p)->value.string;
  936.           break;
  937.          }
  938.       }
  939.     if(user)
  940.       {
  941.        userpass=(char*)malloc(strlen(user)+strlen(pass)+2);
  942.        strcpy(userpass,user);
  943.        strcat(userpass,":");
  944.        strcat(userpass,pass);
  945.       }
  946.    }
  947.  return(userpass);
  948. }
  949. /*++++++++++++++++++++++++++++++++++++++
  950.   Check if the specified URL is to be indexed.
  951.   int IsNotIndexed Return true if it is not to be indexed.
  952.   URL *Url The URL to check.
  953.   char *index The type of index that is being checked.
  954.   ++++++++++++++++++++++++++++++++++++++*/
  955. int IsNotIndexed(URL *Url,char *index)
  956. {
  957.  KeyPair **p;
  958.  KeyPair **special=NULL;
  959.  if(DontIndexOutgoing && !strcmp(index,"outgoing"))
  960.     special=DontIndexOutgoing;
  961.  else if(DontIndexLatest && !strcmp(index,"latest"))
  962.    special=DontIndexLatest;
  963.  else if(DontIndexMonitor && !strcmp(index,"monitor"))
  964.     special=DontIndexMonitor;
  965.  else if(DontIndexHost && !strcmp(index,"host"))
  966.     special=DontIndexHost;
  967.  if(special)
  968.     for(p=special;(*p)!=&KeyPairEnd;p++)
  969.       {
  970.        int match=match_url_specification((*p)->value.urlspec,Url->proto,Url->host,Url->path,Url->args);
  971.        if(match)
  972.           return(!(*p)->value.urlspec->negated);
  973.       }
  974.  if(DontIndex)
  975.     for(p=DontIndex;(*p)!=&KeyPairEnd;p++)
  976.       {
  977.        int match=match_url_specification((*p)->key.urlspec,Url->proto,Url->host,Url->path,Url->args);
  978.        if(match)
  979.           return(!(*p)->key.urlspec->negated);
  980.       }
  981.  return(0);
  982. }
  983. /*++++++++++++++++++++++++++++++++++++++
  984.   Check if a specified protocol and host is aliased to another host.
  985.   int IsAliased Returns non-zero if this is host is aliased to another host.
  986.   char *proto The protocol to check.
  987.   char *host The hostname to check.
  988.   char *path The pathname to check.
  989.   char **new_proto The protocol of the alias.
  990.   char **new_host The hostname of the alias.
  991.   char **new_path The pathname of the alias.
  992.   ++++++++++++++++++++++++++++++++++++++*/
  993. int IsAliased(char *proto,char *host,char *path,char **new_proto,char **new_host,char **new_path)
  994. {
  995.  KeyPair **a;
  996.  *new_proto=*new_host=*new_path=NULL;
  997.  if(Aliases)
  998.     for(a=Aliases;(*a)!=&KeyPairEnd;a++)
  999.        if(match_url_specification((*a)->key.urlspec,proto,host,path,NULL))
  1000.          {
  1001.           if((*a)->value.urlspec->proto)
  1002.             {
  1003.              *new_proto=(char*)malloc(strlen((*a)->value.urlspec->proto)+1);
  1004.              strcpy(*new_proto,(*a)->value.urlspec->proto);
  1005.             }
  1006.           else
  1007.             {
  1008.              *new_proto=(char*)malloc(strlen(proto)+1);
  1009.              strcpy(*new_proto,proto);
  1010.             }
  1011.           if((*a)->value.urlspec->host)
  1012.             {
  1013.              *new_host=(char*)malloc(strlen((*a)->value.urlspec->host)+8);
  1014.              strcpy(*new_host,(*a)->value.urlspec->host);
  1015.              if((*a)->value.urlspec->port>0)
  1016.                 sprintf((*new_host)+strlen(*new_host),":%d",(*a)->value.urlspec->port);
  1017.             }
  1018.           else
  1019.             {
  1020.              *new_host=(char*)malloc(strlen(host)+1);
  1021.              strcpy(*new_host,host);
  1022.             }
  1023.           if((*a)->value.urlspec->path)
  1024.             {
  1025.              int oldlen=(*a)->key.urlspec->path?strlen((*a)->key.urlspec->path):0;
  1026.              int newlen=(*a)->value.urlspec->path?strlen((*a)->value.urlspec->path):0;
  1027.              *new_path=(char*)malloc(newlen-oldlen+strlen(path)+1);
  1028.              if(newlen)
  1029.                {
  1030.                 strcpy(*new_path,(*a)->value.urlspec->path);
  1031.                 if((*new_path)[newlen-1]=='/')
  1032.                    (*new_path)[newlen-1]=0;
  1033.                }
  1034.              strcat(*new_path,path+oldlen);
  1035.             }
  1036.           else
  1037.             {
  1038.              *new_path=(char*)malloc(strlen(path)+1);
  1039.              strcpy(*new_path,path);
  1040.             }
  1041.          }
  1042.  return(!!*new_proto);
  1043. }
  1044. /*++++++++++++++++++++++++++++++++++++++
  1045.   Search through the cache for the symbolic links that are also alias entries.
  1046.   KeyPair **DefaultAliasLinks Return the list of links.
  1047.   ++++++++++++++++++++++++++++++++++++++*/
  1048. static KeyPair **DefaultAliasLinks(void)
  1049. {
  1050.  KeyPair **links=NULL;
  1051.  int p;
  1052.  for(p=0;p<NProtocols;p++)
  1053.    {
  1054.     struct stat buf;
  1055.     if(!lstat(Protocols[p].name,&buf) && S_ISDIR(buf.st_mode))
  1056.       {
  1057.        DIR *dir2;
  1058.        struct dirent* ent2;
  1059.        if(chdir(Protocols[p].name))
  1060.          {PrintMessage(Warning,"Cannot change to directory '%s' [%!s]; no aliases.",Protocols[p].name);continue;}
  1061.        /* Open the spool directory. */
  1062.        dir2=opendir(".");
  1063.        if(!dir2)
  1064.          {PrintMessage(Warning,"Cannot open directory '%s' [%!s]; no aliases.",Protocols[p].name);chdir("..");continue;}
  1065.        ent2=readdir(dir2);  /* skip .  */
  1066.        if(!ent2)
  1067.          {PrintMessage(Warning,"Cannot read directory '%s' [%!s]; no aliases.",Protocols[p].name);closedir(dir2);chdir("..");continue;}
  1068.        ent2=readdir(dir2);  /* skip .. */
  1069.        /* Search for all of the symbolic links. */
  1070.        while((ent2=readdir(dir2)))
  1071.          {
  1072.           struct stat buf2;
  1073.           char *host=ent2->d_name;
  1074.           if(!lstat(host,&buf2) && S_ISLNK(buf2.st_mode))
  1075.              PrintMessage(Warning,"Symbolic links (like '%s/%s') are obsoleted by the 'Alias' configuration file section.n",Protocols[p].name,ent2->d_name);
  1076.          }
  1077.        closedir(dir2);
  1078.        chdir("..");
  1079.       }
  1080.    }
  1081.  return(links);
  1082. }
  1083. /*++++++++++++++++++++++++++++++++++++++
  1084.   Determine the age to use when purging for a specified URL.
  1085.   int WhatPurgeAge Return the age in days.
  1086.   char *proto The name of the protocol used.
  1087.   char *host The name of the host to be purged.
  1088.   char *path The pathname of the URL to be purged.
  1089.   char *args The arguments of the URL to be purged.
  1090.   ++++++++++++++++++++++++++++++++++++++*/
  1091. int WhatPurgeAge(char *proto,char *host,char *path,char *args)
  1092. {
  1093.  KeyPair **p;
  1094.  int age=DefaultPurgeAge;
  1095.  int matchlen=0,ml;
  1096.  if(PurgeAges)
  1097.     for(p=PurgeAges;(*p)!=&KeyPairEnd;p++)
  1098.        if((ml=match_url_specification((*p)->key.urlspec,proto,host,path,args)))
  1099.           if(ml>matchlen)
  1100.             {
  1101.              matchlen=ml;
  1102.              age=(*p)->value.integer;
  1103.             }
  1104.  if(PurgeDontGet && IsNotGot(proto,host,path,args))
  1105.     age=0;
  1106.  if(PurgeDontCache && (IsNotCached(proto,host,path,args) || IsLocalNetHost(host)))
  1107.     age=0;
  1108.  return(age);
  1109. }
  1110. /*++++++++++++++++++++++++++++++++++++++
  1111.   Check if a protocol, host and path match a URL-SPECIFICATION in the config file.
  1112.   int match_url_specification Return the matching length if true else 0.
  1113.   UrlSpec *spec The URL-SPECIFICATION.
  1114.   char *proto The protocol.
  1115.   char *host The host.
  1116.   char *path The path.
  1117.   char *args The arguments.
  1118.   ++++++++++++++++++++++++++++++++++++++*/
  1119. static int match_url_specification(UrlSpec *spec,char *proto,char *host,char *path,char *args)
  1120. {
  1121.  int match=0;
  1122.  char *colon=strchr(host,':');
  1123.  if(colon)
  1124.     *colon=0;
  1125.  if((!spec->proto || !strcmp(spec->proto,proto)) &&
  1126.     (!spec->host || wildcard_match(host,spec->host)) &&
  1127.     (spec->port==-1 || (!colon && spec->port==0) || (colon && atoi(colon+1)==spec->port)) &&
  1128.     (!spec->path || wildcard_match(path,spec->path)) &&
  1129.     (!spec->args || (args && wildcard_match(args,spec->args)) || (!args && *spec->args==0)))
  1130.    {
  1131.     match=(spec->proto?strlen(spec->proto):0)+
  1132.           (spec->host?strlen(spec->host):0)+
  1133.           (spec->path?strlen(spec->path):0)+
  1134.           (spec->args?strlen(spec->args):0)+1;
  1135.    }
  1136.  if(colon)
  1137.     *colon=':';
  1138.  return(match);
  1139. }
  1140. /*++++++++++++++++++++++++++++++++++++++
  1141.   Do a match using a wildcard specified with '*' in it.
  1142.   int wildcard_match returns 1 if there is a match.
  1143.   char *string The fixed string that is being matched.
  1144.   char *pattern The pattern to match against.
  1145.   ++++++++++++++++++++++++++++++++++++++*/
  1146. static int wildcard_match(char *string,char *pattern)
  1147. {
  1148.  int i,nstars=0;
  1149.  for(i=0;pattern[i];i++)
  1150.     if(pattern[i]=='*')
  1151.        nstars++;
  1152.  if(nstars)
  1153.    {
  1154.     int len_pat=strlen(pattern);
  1155.     int len_str=strlen(string);
  1156.     if((len_pat-nstars)>len_str)
  1157.       {
  1158.        if(!strcmp(string,"/") && !strcmp(pattern,"/*/"))
  1159.           return(1);
  1160.        else
  1161.           return(0);
  1162.       }
  1163.     else
  1164.       {
  1165.        char *str_beg=NULL,*str_mid=NULL,*str_end=NULL;
  1166.        int len_beg=0,len_mid=0,len_end=0;
  1167.        /* Look for a star at the start. */
  1168.        if(pattern[0]!='*')
  1169.          {
  1170.           str_beg=pattern;
  1171.           while(pattern[len_beg]!='*')
  1172.              len_beg++;
  1173.           if(len_beg>len_str || strncmp(str_beg,string,len_beg))
  1174.              return(0);
  1175.          }
  1176.        /* Look for a star at the end. */
  1177.        if(pattern[strlen(pattern)-1]!='*')
  1178.          {
  1179.           str_end=pattern+len_pat-2;
  1180.           while(*str_end!='*')
  1181.              str_end--;
  1182.           str_end++;
  1183.           len_end=pattern+len_pat-str_end;
  1184.           if(len_end>len_str || strncmp(str_end,string+len_str-len_end,len_end))
  1185.              return(0);
  1186.          }
  1187.        /* Check the rest. */
  1188.        if(nstars==1)
  1189.           return(1);
  1190.        else if(nstars==2)
  1191.          {
  1192.           char *copy=malloc(len_pat+1),*p;
  1193.           strcpy(copy,pattern);
  1194.           copy[len_beg]=0;
  1195.           copy[len_pat-1-len_end]=0;
  1196.           str_mid=copy+len_beg+1;
  1197.           len_mid=len_pat-len_beg-len_end-2;
  1198.           if((p=strstr(string+len_beg,str_mid)) && (p+len_mid)<=(string+len_str-len_end))
  1199.             {free(copy);return(1);}
  1200.           else
  1201.             {free(copy);return(0);}
  1202.          }
  1203.        else
  1204.           return(0);
  1205.       }
  1206.    }
  1207.  return(!strcmp(string,pattern));
  1208. }
  1209. #endif /* !defined(STARTUP_ONLY) */
  1210. /*++++++++++++++++++++++++++++++++++++++
  1211.   Read the data from the file.
  1212.   FILE *config The file to read from.
  1213.   ++++++++++++++++++++++++++++++++++++++*/
  1214. static void ReadFile(FILE *config)
  1215. {
  1216.  char *line;
  1217.  line_no=0;
  1218.  file_name=ConfigFile;
  1219.  while((line=ReadLine(config)))
  1220.    {
  1221.     int i;
  1222.     for(i=0;sections[i];i++)
  1223.        if(!strcmp(sections[i]->name,line))
  1224.           break;
  1225.     if(!sections[i])
  1226.       {errmsg=(char*)malloc(48+strlen(line));sprintf(errmsg,"Unrecognised section label '%s'.",line);return;}
  1227.     if(!(line=ReadLine(config)))
  1228.       {errmsg=(char*)malloc(32);strcpy(errmsg,"Unexpected end of file.");return;}
  1229.     if(*line!='{' && *line!='[')
  1230.       {errmsg=(char*)malloc(48);strcpy(errmsg,"Start of section must be '{' or '['.");return;}
  1231.     if(*(line+1))
  1232.       {*(line+1)=0;errmsg=(char*)malloc(48);sprintf(errmsg,"Start of section '%c' has trailing junk.",*line);return;}
  1233.     if(!first_time && sections[i]==*sections)
  1234.       {
  1235.        while((line=ReadLine(config)))
  1236.           if(*line=='}' || *line==']')
  1237.              break;
  1238.       }
  1239.     else if(*line=='{')
  1240.       {
  1241.        ReadSection(config,sections[i]);
  1242.       }
  1243.     else if(*line=='[')
  1244.       {
  1245.        int save_line_no;
  1246.        char *name,*r;
  1247.        FILE *file;
  1248.        if(!(line=ReadLine(config)))
  1249.          {errmsg=(char*)malloc(32);strcpy(errmsg,"Unexpected end of file.");return;}
  1250.        name=(char*)malloc(strlen(ConfigFile)+strlen(line)+1);
  1251.        strcpy(name,ConfigFile);
  1252.        r=name+strlen(name)-1;
  1253.        while(r>name && *r!='/')
  1254.           r--;
  1255.        strcpy(r+1,line);
  1256.        if(!(file=fopen(name,"r")))
  1257.          {errmsg=(char*)malloc(32+strlen(name));sprintf(errmsg,"Cannot open included file '%s.",name);return;}
  1258.        save_line_no=line_no;
  1259.        file_name=name;
  1260.        ReadSection(file,sections[i]);
  1261.        line_no=save_line_no;
  1262.        file_name=ConfigFile;
  1263.        fclose(file);
  1264.        if(!(line=ReadLine(config)))
  1265.          {errmsg=(char*)malloc(32);strcpy(errmsg,"Unexpected end of file.");return;}
  1266.        if(*line!=']')
  1267.          {errmsg=(char*)malloc(48);strcpy(errmsg,"End of section must be '}' or ']'.");return;}
  1268.       }
  1269.     if(errmsg)
  1270.        return;
  1271. #if defined(STARTUP_ONLY)
  1272.     if(sections[i]==*sections)
  1273.        break;
  1274. #endif
  1275.    }
  1276. }
  1277. /*++++++++++++++++++++++++++++++++++++++
  1278.   Read all the data from a section.
  1279.   FILE *config The file to read from.
  1280.   Section *section The section to read.
  1281.   ++++++++++++++++++++++++++++++++++++++*/
  1282. static void ReadSection(FILE *config,Section *section)
  1283. {
  1284.  char *line;
  1285.  while((line=ReadLine(config)))
  1286.    {
  1287.     if(*line=='}' || *line==']')
  1288.       {
  1289.        if(*(line+1))
  1290.          {*(line+1)=0;errmsg=(char*)malloc(48);sprintf(errmsg,"End of section '%c' has trailing junk.",*line);return;}
  1291.        return;
  1292.       }
  1293.     else
  1294.       {
  1295.        int i;
  1296.        char *l=line,*r=NULL;
  1297.        for(i=0;section->entries[i].name;i++)
  1298.           if(!*section->entries[i].name || !strncmp(section->entries[i].name,l,strlen(section->entries[i].name)))
  1299.             {
  1300.              char *ll;
  1301.              if(*section->entries[i].name)
  1302.                {
  1303.                 ll=l+strlen(section->entries[i].name);
  1304.                 if(*ll && *ll!='=' && !isspace(*ll))
  1305.                    continue;
  1306.                }
  1307.              else
  1308.                {
  1309.                 ll=l;
  1310.                 while(*ll && *ll!='=' && !isspace(*ll))
  1311.                    ll++;
  1312.                }
  1313.              if(section->entries[i].right_type==None ||
  1314.                 (section->entries[i].right_type==OptionalUrl && !strchr(line, '=')))
  1315.                {
  1316.                 *ll=0;
  1317.                 r=NULL;
  1318.                }
  1319.              else
  1320.                {
  1321.                 r=strchr(line,'=');
  1322.                 if(!r)
  1323.                   {errmsg=(char*)malloc(32);strcpy(errmsg,"No equal sign for entry.");return;}
  1324.                 *ll=0;
  1325.                 if(!*l)
  1326.                   {errmsg=(char*)malloc(48);strcpy(errmsg,"Nothing to the left of the equal sign.");return;}
  1327.                 r++;
  1328.                 while(isspace(*r))
  1329.                    r++;
  1330.                }
  1331.              break;
  1332.             }
  1333.        if(!section->entries[i].name)
  1334.          {errmsg=(char*)malloc(32+strlen(l));sprintf(errmsg,"Unrecognised entry label '%s'.",l);return;}
  1335.        if(ParseEntry(&section->entries[i],l,r))
  1336.           return;
  1337.       }
  1338.    }
  1339. }
  1340. /*++++++++++++++++++++++++++++++++++++++
  1341.   Read a line from the configuration file, skipping over comments and blank lines.
  1342.   char *ReadLine Returns a pointer to the first thing in the line.
  1343.   FILE *config The file to read from.
  1344.   ++++++++++++++++++++++++++++++++++++++*/
  1345. static char *ReadLine(FILE *config)
  1346. {
  1347.  static char *line=NULL;
  1348.  char *l=NULL,*r;
  1349.  while((line=fgets_realloc(line,config)))
  1350.    {
  1351.     l=line;
  1352.     r=line+strlen(line)-1;
  1353.     line_no++;
  1354.     while(isspace(*l))
  1355.        l++;
  1356.     if(!*l || *l=='#')
  1357.        continue;
  1358.     while(r>l && isspace(*r))
  1359.        *r--=0;
  1360.     break;
  1361.    }
  1362.  if(!line)
  1363.     l=NULL;
  1364.  return(l);
  1365. }
  1366. /*++++++++++++++++++++++++++++++++++++++
  1367.   Parse an entry from the file.
  1368.   int ParseEntry Return 1 in case of error.
  1369.   Entry *entries The list of matching entry in the section.
  1370.   char *left The string to the left of the equals sign.
  1371.   char *right The string to the right of the equals sign.
  1372.   ++++++++++++++++++++++++++++++++++++++*/
  1373. static int ParseEntry(Entry *entry,char *left,char *right)
  1374. {
  1375.  if(entry->list)
  1376.    {
  1377.     KeyPair **p,*new=(KeyPair*)malloc(sizeof(KeyPair));
  1378.     int i;
  1379.     if(entry->left_type==Fixed)
  1380.        new->key.string=entry->name;
  1381.     else
  1382.        if(ParseValue(left,entry->left_type,(void*)&new->key,0))
  1383.          {free(new);return(1);}
  1384.     if(entry->right_type==None || !right)
  1385.        new->value.string=NULL;
  1386.     else
  1387.        if(ParseValue(right,entry->right_type,(void*)&new->value,1))
  1388.          {free(new);return(1);}
  1389.     if(!*(KeyPair***)entry->pointer)
  1390.       {
  1391.        *(KeyPair***)entry->pointer=(KeyPair**)malloc(8*sizeof(KeyPair*));
  1392.        **(KeyPair***)entry->pointer=&KeyPairEnd;
  1393.       }
  1394.     p=*(KeyPair***)entry->pointer;
  1395.     for(i=0;(*p)!=&KeyPairEnd;p++,i++);
  1396.     if(i%8==7)
  1397.        *(KeyPair***)entry->pointer=(KeyPair**)realloc(*(void**)entry->pointer,(i+9)*sizeof(KeyPair*));
  1398.     for(p=*(KeyPair***)entry->pointer;(*p)!=&KeyPairEnd;p++);
  1399.     *p=new;
  1400.     p++;
  1401.     *p=&KeyPairEnd;
  1402.    }
  1403.  else
  1404.     if(ParseValue(right,entry->right_type,entry->pointer,1))
  1405.        return(1);
  1406.  return(0);
  1407. }
  1408. /*++++++++++++++++++++++++++++++++++++++
  1409.   Parse the text and put a value into the location.
  1410.   int ParseValue Returns non-zero in case of error.
  1411.   char *text The text string to parse.
  1412.   ConfigType type The type we are looking for.
  1413.   void *pointer The location to store the key or value.
  1414.   int rhs Set to true if this is the right hand side.
  1415.   ++++++++++++++++++++++++++++++++++++++*/
  1416. static int ParseValue(char *text,ConfigType type,void *pointer,int rhs)
  1417. {
  1418. #define INTEGER(pointer) (*((int*)     pointer))
  1419. #define MODE_T(pointer)  (*((mode_t*)  pointer))
  1420. #define STRING(pointer)  (*((char**)   pointer))
  1421. #define URLSPEC(pointer) (*((UrlSpec**)pointer))
  1422.  switch(type)
  1423.    {
  1424.    case Fixed:
  1425.    case None:
  1426.     break;
  1427.    case CfgMaxServers:
  1428.     if(!*text)
  1429.       {errmsg=(char*)malloc(56);strcpy(errmsg,"Expecting a maximum server count, got nothing.");}
  1430.     else if(!isanumber(text))
  1431.       {errmsg=(char*)malloc(48+strlen(text));sprintf(errmsg,"Expecting a maximum server count, got '%s'.",text);}
  1432.     else
  1433.       {
  1434.        INTEGER(pointer)=atoi(text);
  1435.        if(INTEGER(pointer)<=0 || INTEGER(pointer)>MAX_SERVERS)
  1436.          {errmsg=(char*)malloc(48);sprintf(errmsg,"Invalid maximum server count: %d.",INTEGER(pointer));}
  1437.       }
  1438.     break;
  1439.    case CfgMaxFetchServers:
  1440.     if(!*text)
  1441.       {errmsg=(char*)malloc(56);strcpy(errmsg,"Expecting a maximum fetch server count, got nothing.");}
  1442.     else if(!isanumber(text))
  1443.       {errmsg=(char*)malloc(56+strlen(text));sprintf(errmsg,"Expecting a maximum fetch server count, got '%s'.",text);}
  1444.     else
  1445.       {
  1446.        INTEGER(pointer)=atoi(text);
  1447.        if(INTEGER(pointer)<=0 || INTEGER(pointer)>MAX_FETCH_SERVERS)
  1448.          {errmsg=(char*)malloc(48);sprintf(errmsg,"Invalid maximum fetch server count: %d.",INTEGER(pointer));}
  1449.       }
  1450.     break;
  1451.    case CfgLogLevel:
  1452.     if(!*text)
  1453.       {errmsg=(char*)malloc(48);strcpy(errmsg,"Expecting a log level, got nothing.");}
  1454.     else if(strcasecmp(text,"debug")==0)
  1455.        INTEGER(pointer)=Debug;
  1456.     else if(strcasecmp(text,"info")==0)
  1457.        INTEGER(pointer)=Inform;
  1458.     else if(strcasecmp(text,"important")==0)
  1459.        INTEGER(pointer)=Important;
  1460.     else if(strcasecmp(text,"warning")==0)
  1461.        INTEGER(pointer)=Warning;
  1462.     else if(strcasecmp(text,"fatal")==0)
  1463.        INTEGER(pointer)=Fatal;
  1464.     else
  1465.       {errmsg=(char*)malloc(48+strlen(text));sprintf(errmsg,"Expecting a log level, got '%s'.",text);}
  1466.     break;
  1467.    case Boolean:
  1468.     if(!*text)
  1469.       {errmsg=(char*)malloc(48);strcpy(errmsg,"Expecting a Boolean, got nothing.");}
  1470.     else if(!strcasecmp(text,"yes") || !strcasecmp(text,"true"))
  1471.        INTEGER(pointer)=1;
  1472.     else if(!strcasecmp(text,"no") || !strcasecmp(text,"false"))
  1473.        INTEGER(pointer)=0;
  1474.     else
  1475.       {errmsg=(char*)malloc(48+strlen(text));sprintf(errmsg,"Expecting a Boolean, got '%s'.",text);}
  1476.     break;
  1477.    case PortNumber:
  1478.     if(!*text)
  1479.       {errmsg=(char*)malloc(48);strcpy(errmsg,"Expecting a port number, got nothing.");}
  1480.     else if(!isanumber(text))
  1481.       {errmsg=(char*)malloc(40+strlen(text));sprintf(errmsg,"Expecting a port number, got '%s'.",text);}
  1482.     else
  1483.       {
  1484.        INTEGER(pointer)=atoi(text);
  1485.        if(INTEGER(pointer)<=0 || INTEGER(pointer)>65535)
  1486.          {errmsg=(char*)malloc(32);sprintf(errmsg,"Invalid port number %d.",INTEGER(pointer));}
  1487.       }
  1488.     break;
  1489.    case AgeDays:
  1490.     if(!*text)
  1491.       {errmsg=(char*)malloc(48);strcpy(errmsg,"Expecting an age in days, got nothing.");}
  1492.     else if(!isanumber(text))
  1493.       {errmsg=(char*)malloc(40+strlen(text));sprintf(errmsg,"Expecting an age in days, got '%s'.",text);}
  1494.     else
  1495.        INTEGER(pointer)=atoi(text);
  1496.     break;
  1497.    case TimeSecs:
  1498.     if(!*text)
  1499.       {errmsg=(char*)malloc(48);strcpy(errmsg,"Expecting a time in seconds, got nothing.");}
  1500.     else if(!isanumber(text))
  1501.       {errmsg=(char*)malloc(40+strlen(text));sprintf(errmsg,"Expecting an time in seconds, got '%s'.",text);}
  1502.     else
  1503.        INTEGER(pointer)=atoi(text);
  1504.     break;
  1505.    case CacheSize:
  1506.     if(!*text)
  1507.       {errmsg=(char*)malloc(48);strcpy(errmsg,"Expecting a cache size in MB, got nothing.");}
  1508.     else if(!isanumber(text))
  1509.       {errmsg=(char*)malloc(40+strlen(text));sprintf(errmsg,"Expecting a cache size in MB, got '%s'.",text);}
  1510.     else
  1511.       {
  1512.        INTEGER(pointer)=atoi(text);
  1513.        if(INTEGER(pointer)<0)
  1514.          {errmsg=(char*)malloc(48);sprintf(errmsg,"Invalid cache size %d.",INTEGER(pointer));}
  1515.       }
  1516.     break;
  1517.    case FileSize:
  1518.     if(!*text)
  1519.       {errmsg=(char*)malloc(48);strcpy(errmsg,"Expecting a file size in kB, got nothing.");}
  1520.     else if(!isanumber(text))
  1521.       {errmsg=(char*)malloc(40+strlen(text));sprintf(errmsg,"Expecting a file size in kB, got '%s'.",text);}
  1522.     else
  1523.       {
  1524.        INTEGER(pointer)=atoi(text);
  1525.        if(INTEGER(pointer)<0)
  1526.          {errmsg=(char*)malloc(48);sprintf(errmsg,"Invalid file size %d.",INTEGER(pointer));}
  1527.       }
  1528.     break;
  1529.    case Percentage:
  1530.     if(!*text)
  1531.       {errmsg=(char*)malloc(48);strcpy(errmsg,"Expecting a percentage, got nothing.");}
  1532.     else if(!isanumber(text))
  1533.       {errmsg=(char*)malloc(40+strlen(text));sprintf(errmsg,"Expecting a percentage, got '%s'.",text);}
  1534.     else
  1535.       {
  1536.        INTEGER(pointer)=atoi(text);
  1537.        if(INTEGER(pointer)<0)
  1538.          {errmsg=(char*)malloc(48);sprintf(errmsg,"Invalid percentage %d.",INTEGER(pointer));}
  1539.       }
  1540.     break;
  1541.    case UserId:
  1542.     if(!*text)
  1543.       {errmsg=(char*)malloc(48);strcpy(errmsg,"Expecting a username or uid, got nothing.");}
  1544.     else
  1545.       {
  1546.        int uid;
  1547.        struct passwd *userInfo=getpwnam(text);
  1548.        if(userInfo)
  1549.           uid=userInfo->pw_uid;
  1550.        else
  1551.          {
  1552.           if(sscanf(text,"%d",&uid)!=1)
  1553.             {errmsg=(char*)malloc(32+strlen(text));sprintf(errmsg,"Invalid user %s.",text);}
  1554.           else if(!getpwuid(uid))
  1555.             {errmsg=(char*)malloc(32);sprintf(errmsg,"Unknown user id %d.",uid);}
  1556.          }
  1557.        INTEGER(pointer)=uid;
  1558.       }
  1559.     break;
  1560.    case GroupId:
  1561.     if(!*text)
  1562.       {errmsg=(char*)malloc(48);strcpy(errmsg,"Expecting a group name or gid, got nothing.");}
  1563.     else
  1564.       {
  1565.        int gid;
  1566.        struct group *groupInfo=getgrnam(text);
  1567.        if(groupInfo)
  1568.           gid=groupInfo->gr_gid;
  1569.        else
  1570.          {
  1571.           if(sscanf(text,"%d",&gid)!=1)
  1572.             {errmsg=(char*)malloc(32+strlen(text));sprintf(errmsg,"Invalid group %s.",text);}
  1573.           else if(!getgrgid(gid))
  1574.             {errmsg=(char*)malloc(32);sprintf(errmsg,"Unknown group id %d.",gid);}
  1575.          }
  1576.        INTEGER(pointer)=gid;
  1577.       }
  1578.     break;
  1579.    case String:
  1580.     if(!*text || !strcasecmp(text,"none"))
  1581.        STRING(pointer)=NULL;
  1582.     else
  1583.       {
  1584.        STRING(pointer)=(char*)malloc(strlen(text)+1);
  1585.        strcpy(STRING(pointer),text);
  1586.       }
  1587.     break;
  1588.    case PathName:
  1589.     if(!*text)
  1590.       {errmsg=(char*)malloc(48);strcpy(errmsg,"Expecting a pathname, got nothing.");}
  1591.     else if(*text!='/')
  1592.       {errmsg=(char*)malloc(48+strlen(text));sprintf(errmsg,"Expecting an absolute pathname, got '%s'.",text);}
  1593.     else
  1594.       {
  1595.        STRING(pointer)=(char*)malloc(strlen(text)+1);
  1596.        strcpy(STRING(pointer),text);
  1597.       }
  1598.     break;
  1599.    case FileExt:
  1600.     if(!*text)
  1601.       {errmsg=(char*)malloc(40);strcpy(errmsg,"Expecting a file extension, got nothing.");}
  1602.     else if(*text!='.')
  1603.       {errmsg=(char*)malloc(40+strlen(text));sprintf(errmsg,"Expecting a file extension, got '%s'.",text);}
  1604.     else
  1605.       {
  1606.        STRING(pointer)=(char*)malloc(strlen(text)+1);
  1607.        strcpy(STRING(pointer),text);
  1608.       }
  1609.     break;
  1610.    case FileMode:
  1611.     if(!*text)
  1612.       {errmsg=(char*)malloc(40);strcpy(errmsg,"Expecting a file permissions mode, got nothing.");}
  1613.     else if(!isanumber(text) || *text!='0')
  1614.       {errmsg=(char*)malloc(48+strlen(text));sprintf(errmsg,"Expecting a file permissions mode, got '%s'.",text);}
  1615.     else
  1616.        MODE_T(pointer)=strtol(text,NULL,8);
  1617.     break;
  1618.    case MIMEType:
  1619.      if(!*text)
  1620.        {errmsg=(char*)malloc(40);strcpy(errmsg,"Expecting a MIME Type, got nothing.");}
  1621.      else
  1622.        {
  1623.         char *slash=strchr(text,'/');
  1624.         if(!slash)
  1625.           {errmsg=(char*)malloc(48+strlen(text));sprintf(errmsg,"Expecting a MIME Type/Subtype, got '%s'.",text);}
  1626.         STRING(pointer)=(char*)malloc(strlen(text)+1);
  1627.         strcpy(STRING(pointer),text);
  1628.        }
  1629.     break;
  1630.    case Host:
  1631.      if(!*text)
  1632.        {errmsg=(char*)malloc(40);strcpy(errmsg,"Expecting a hostname, got nothing.");}
  1633.      else
  1634.        {
  1635.         char *colon=strchr(text,':'),*p;
  1636.         if(colon)
  1637.           {errmsg=(char*)malloc(56+strlen(text));sprintf(errmsg,"Expecting a hostname not a port number, got '%s'.",text);}
  1638.         else
  1639.           {
  1640.            STRING(pointer)=(char*)malloc(strlen(text)+1);
  1641.            for(p=text;*p;p++)
  1642.               *p=tolower(*p);
  1643.            strcpy(STRING(pointer),text);
  1644.           }
  1645.        }
  1646.      break;
  1647.    case HostAndPortOrNone:
  1648.     if(rhs && (!*text || !strcasecmp(text,"none")))
  1649.       {
  1650.        STRING(pointer)=NULL;
  1651.        break;
  1652.       }
  1653.     /* fall through */
  1654.    case HostAndPort:
  1655.     if(!*text)
  1656.       {errmsg=(char*)malloc(48);strcpy(errmsg,"Expecting a hostname (and port), got nothing.");}
  1657.     else
  1658.       {
  1659.        char *colon=strchr(text,':'),*p;
  1660.        if(*text==':')
  1661.          {errmsg=(char*)malloc(48+strlen(text));sprintf(errmsg,"Expecting a hostname before the ':', got '%s'.",text);}
  1662.        else
  1663.          {
  1664.           if(colon && (!isanumber(colon+1) || atoi(colon+1)<=0 || atoi(colon+1)>65535))
  1665.             {errmsg=(char*)malloc(32+strlen(colon));sprintf(errmsg,"Invalid port number %s.",colon+1);}
  1666.           else
  1667.             {
  1668.              STRING(pointer)=(char*)malloc(strlen(text)+1);
  1669.              for(p=text;*p;p++)
  1670.                 *p=tolower(*p);
  1671.              strcpy(STRING(pointer),text);
  1672.             }
  1673.          }
  1674.       }
  1675.     break;
  1676.    case UserPass:
  1677.     if(!*text)
  1678.       {errmsg=(char*)malloc(48);strcpy(errmsg,"Expecting a username and password, got nothing.");}
  1679.     else if(!strchr(text,':'))
  1680.       {errmsg=(char*)malloc(48+strlen(text));sprintf(errmsg,"Expecting a username and password, got '%s'.",text);}
  1681.     else
  1682.        STRING(pointer)=Base64Encode(text,strlen(text));
  1683.     break;
  1684.    case Url:
  1685.    case OptionalUrl:
  1686.     if(!*text || !strcasecmp(text,"none"))
  1687.        STRING(pointer)=NULL;
  1688.     else
  1689.       {
  1690.        URL *tempUrl=SplitURL(text);
  1691.        if(!tempUrl->Protocol)
  1692.          {errmsg=(char*)malloc(32+strlen(text));sprintf(errmsg,"Expecting a URL, got '%s'.",text);}
  1693.        else
  1694.          {
  1695.           STRING(pointer)=(char*)malloc(strlen(text)+1);
  1696.           strcpy(STRING(pointer),text);
  1697.           FreeURL(tempUrl);
  1698.          }
  1699.       }
  1700.     break;
  1701.    case UrlSpecification:
  1702.     if(!*text)
  1703.       {errmsg=(char*)malloc(64);strcpy(errmsg,"Expecting a URL-SPECIFICATION, got nothing.");}
  1704.     else
  1705.       {
  1706.        char *p,*orgtext=text;
  1707.        URLSPEC(pointer)=(UrlSpec*)malloc(sizeof(UrlSpec));
  1708.        URLSPEC(pointer)->negated=0;
  1709.        URLSPEC(pointer)->proto=NULL;
  1710.        URLSPEC(pointer)->host=NULL;
  1711.        URLSPEC(pointer)->port=-1;
  1712.        URLSPEC(pointer)->path=NULL;
  1713.        URLSPEC(pointer)->args=NULL;
  1714.        if(!strcmp("default",text))
  1715.           break;
  1716.        /* ! */
  1717.        if(*text=='!')
  1718.          {
  1719.           URLSPEC(pointer)->negated=1;
  1720.           text++;
  1721.          }
  1722.        /* protocol */
  1723.        if(!strncmp(text,"*://",4))
  1724.          {
  1725.           p=text+4;
  1726.           URLSPEC(pointer)->proto=NULL;
  1727.          }
  1728.        else if(!strncmp(text,"://",3))
  1729.          {
  1730.           p=text+3;
  1731.           URLSPEC(pointer)->proto=NULL;
  1732.          }
  1733.        else if((p=strstr(text,"://")))
  1734.          {
  1735.           URLSPEC(pointer)->proto=(char*)malloc(p-text+1);
  1736.           strncpy(URLSPEC(pointer)->proto,text,p-text);
  1737.           *(URLSPEC(pointer)->proto+(p-text))=0;
  1738.           p+=3;
  1739.          }
  1740.        else
  1741.          {errmsg=(char*)malloc(64+strlen(orgtext));sprintf(errmsg,"Expecting a URL-SPECIFICATION, got this '%s'.",orgtext); break;}
  1742.        if(URLSPEC(pointer)->proto)
  1743.          {
  1744.           char *q;
  1745.           for(q=URLSPEC(pointer)->proto;*q;q++)
  1746.              *q=tolower(*q);
  1747.          }
  1748.        text=p;
  1749.        /* host */
  1750.        if(*text=='*' && (*(text+1)=='/' || !*(text+1)))
  1751.           p=text+1;
  1752.        else if(*text==':')
  1753.           p=text;
  1754.        else if((p=strstr(text,":")))
  1755.          {
  1756.           URLSPEC(pointer)->host=(char*)malloc(p-text+1);
  1757.           strncpy(URLSPEC(pointer)->host,text,p-text);
  1758.           *(URLSPEC(pointer)->host+(p-text))=0;
  1759.          }
  1760.        else if((p=strstr(text,"/")))
  1761.          {
  1762.           URLSPEC(pointer)->host=(char*)malloc(p-text+1);
  1763.           strncpy(URLSPEC(pointer)->host,text,p-text);
  1764.           *(URLSPEC(pointer)->host+(p-text))=0;
  1765.          }
  1766.        else if(*text)
  1767.          {
  1768.           URLSPEC(pointer)->host=(char*)malloc(strlen(text)+1);
  1769.           strcpy(URLSPEC(pointer)->host,text);
  1770.           p=text+strlen(text);
  1771.          }
  1772.        else
  1773.           p=text;
  1774.        if(URLSPEC(pointer)->host)
  1775.          {
  1776.           char *q;
  1777.           for(q=URLSPEC(pointer)->host;*q;q++)
  1778.              *q=tolower(*q);
  1779.          }
  1780.        text=p;
  1781.        /* port */
  1782.        if(*text==':' && isdigit(*(text+1)))
  1783.          {
  1784.           URLSPEC(pointer)->port=atoi(text+1);
  1785.           p=text+1;
  1786.           while(isdigit(*p))
  1787.              p++;
  1788.          }
  1789.        else if(*text==':' && (*(text+1)=='/' || *(text+1)==0))
  1790.          {
  1791.           URLSPEC(pointer)->port=0;
  1792.           p=text+1;
  1793.          }
  1794.        else if(*text==':' && *(text+1)=='*')
  1795.          {
  1796.           p=text+2;
  1797.          }
  1798.        else if(*text==':')
  1799.          {errmsg=(char*)malloc(64+strlen(orgtext));sprintf(errmsg,"Expecting a URL-SPECIFICATION, got this '%s'.",orgtext); break;}
  1800.        text=p;
  1801.        /* path */
  1802.        if(!*text)
  1803.           ;
  1804.        else if(*text=='/' && !*(text+1))
  1805.           p=text+1;
  1806.        else if(*text=='?')
  1807.           ;
  1808.        else if(*text=='/' && (p=strchr(text,'?')))
  1809.          {
  1810.           URLSPEC(pointer)->path=(char*)malloc(p-text+1);
  1811.           strncpy(URLSPEC(pointer)->path,text,p-text);
  1812.           URLSPEC(pointer)->path[p-text]=0;
  1813.          }
  1814.        else if(*text=='/')
  1815.          {
  1816.           URLSPEC(pointer)->path=(char*)malloc(strlen(text)+1);
  1817.           strcpy(URLSPEC(pointer)->path,text);
  1818.           p=text+strlen(text);
  1819.          }
  1820.        else
  1821.          {errmsg=(char*)malloc(64+strlen(orgtext));sprintf(errmsg,"Expecting a URL-SPECIFICATION, got this '%s'.",orgtext); break;}
  1822.        text=p;
  1823.        /* args */
  1824.        if(!*text)
  1825.           ;
  1826.        else if(*text=='?' && !*(text+1))
  1827.           URLSPEC(pointer)->args="";
  1828.        else if(*text=='?')
  1829.          {
  1830.           URLSPEC(pointer)->args=(char*)malloc(strlen(text+1)+1);
  1831.           strcpy(URLSPEC(pointer)->args,text+1);
  1832.          }
  1833.        else
  1834.          {errmsg=(char*)malloc(64+strlen(orgtext));sprintf(errmsg,"Expecting a URL-SPECIFICATION, got this '%s'.",orgtext); break;}
  1835.       }
  1836.     break;
  1837.    }
  1838.  if(errmsg)
  1839.     return(1);
  1840.  else
  1841.     return(0);
  1842. }
  1843. /*++++++++++++++++++++++++++++++++++++++
  1844.   Decide if a string is an integer.
  1845.   int isanumber Returns 1 if it is, 0 if not.
  1846.   const char *string The string that may be an integer.
  1847.   ++++++++++++++++++++++++++++++++++++++*/
  1848. static int isanumber(const char *string)
  1849. {
  1850.  int i=0;
  1851.  if(string[0]=='-' || string[i]=='+')
  1852.     i++;
  1853.  for(;string[i];i++)
  1854.     if(!isdigit(string[i]))
  1855.        return(0);
  1856.  return(1);
  1857. }
  1858. /*+ The old value of the level of error logging, see ErrorLevel in errors.h +*/
  1859. static int old_LogLevel;
  1860. /*+ The old value of the number of days to display in the index of the latest pages. +*/
  1861. static int old_IndexLatestDays;
  1862. /*+ The old value of the option to turn on the modifications in this section. +*/
  1863. static int old_EnableHTMLModifications;
  1864. /*+ The old value of the option of a tag that can be added to the bottom of the spooled pages with the date and some buttons. +*/
  1865. static int old_AddCacheInfo;
  1866. /*+ The old value of the options to modify the anchor tags in the HTML. +*/
  1867. static char *old_AnchorModifyBegin[3],
  1868.             *old_AnchorModifyEnd[3];
  1869. /*+ The old value of the option to disable scripts and scripted actions. +*/
  1870. static int old_DisableHTMLScript;
  1871. /*+ The old value of the option to disable the <blink> tag. +*/
  1872. static int old_DisableHTMLBlink;
  1873. /*+ The old value of the option to disable animated GIFs. +*/
  1874. static int old_DisableAnimatedGIF;
  1875. /*+ The old value of the maximum age of a cached page to use in preference while online. +*/
  1876. static int old_RequestChanged;
  1877. /*+ The old value of the option to only request changes to a page once per session online. +*/
  1878. static int old_RequestChangedOnce;
  1879. /*+ The old value of the option to re-request pages that have expired. +*/
  1880. static int old_RequestExpired;
  1881. /*+ The old value of the option to re-request pages that have the no-cache flag set. +*/
  1882. static int old_RequestNoCache;
  1883. /*+ The old value of the option to allow or ignore the 'Pragma: no-cache' request. +*/
  1884. static int old_PragmaNoCache;
  1885. /*+ The old value of the option to not automatically make requests while offline but to need confirmation. +*/
  1886. static int old_ConfirmRequests;
  1887. /*+ The old value of the amount of time that a socket connection will wait for data. +*/
  1888. static int old_SocketTimeout;
  1889. /*+ The old value of the amount of time that a socket will wait for the intial connection. +*/
  1890. static int old_ConnectTimeout;
  1891. /*+ The old value of the option to retry a failed connection. +*/
  1892. static int old_ConnectRetry;
  1893. /*+ The old value of the list of allowed SSL port numbers. +*/
  1894. static KeyPair **old_SSLAllowPort;
  1895. /*+ The old value of the option to disable the lasttime/prevtime indexs. +*/
  1896. static int old_NoLasttimeIndex;
  1897. /*+ The old value of the option to keep downloads that are interrupted by the user. +*/
  1898. static int old_IntrDownloadKeep;
  1899. /*+ The old value of the option to keep on downloading interrupted pages if +*/
  1900. static int old_IntrDownloadSize;           /*+ smaller than a given size. +*/
  1901. static int old_IntrDownloadPercent;        /*+ more than a given percentage complete. +*/
  1902. /*+ The old value of the option to keep downloads that time out. +*/
  1903. int old_TimeoutDownloadKeep;
  1904. /*+ The old value of the option to also fetch style sheets. +*/
  1905. static int old_FetchStyleSheets;
  1906. /*+ The old value of the option to also fetch images. +*/
  1907. static int old_FetchImages;
  1908. /*+ The old value of the option to also fetch frames. +*/
  1909. static int old_FetchFrames;
  1910. /*+ The old value of the option to also fetch scripts. +*/
  1911. static int old_FetchScripts;
  1912. /*+ The old value of the option to also fetch objects. +*/
  1913. static int old_FetchObjects;
  1914. /*+ The old values of the list of localhost hostnames. +*/
  1915. static KeyPair **old_LocalHost;
  1916. /*+ The old value of the list of local network hostnames. +*/
  1917. static KeyPair **old_LocalNet;
  1918. /*+ The old values of the list of allowed hostnames. +*/
  1919. static KeyPair **old_AllowedConnectHosts;
  1920. /*+ The old values of the list of allowed usernames and passwords. +*/
  1921. static KeyPair **old_AllowedConnectUsers;
  1922. /*+ The old value of the list of URLs not to cache. +*/
  1923. static KeyPair **old_DontCache;
  1924. /*+ The old value of the list of URLs not to get. +*/
  1925. static KeyPair **old_DontGet;
  1926. /*+ The old value of the replacement URL. +*/
  1927. static char *old_DontGetReplacementURL;
  1928. /*+ The old value of the list of URLs not to get. +*/
  1929. static KeyPair **old_DontGetRecursive;
  1930. /*+ The old value of the list of URLs not to request when offline. +*/
  1931. static KeyPair **old_DontRequestOffline;
  1932. /*+ The old value of the list of censored headers. +*/
  1933. static KeyPair **old_CensorHeader;
  1934. /*+ The old value of the flags to cause the referer header to be mangled. +*/
  1935. static int old_RefererSelf,
  1936.            old_RefererSelfDir;
  1937. /*+ The old value of the anon-ftp username. +*/
  1938. static char *old_FTPUserName;
  1939. /*+ The old value of the anon-ftp password. +*/
  1940. static char *old_FTPPassWord;
  1941. /*+ The old value of the information that is needed to allow non-anonymous access, +*/
  1942. static KeyPair **old_FTPAuthHost, /*+ hostname +*/
  1943.                **old_FTPAuthUser, /*+ username +*/
  1944.                **old_FTPAuthPass; /*+ password +*/
  1945. /*+ The old value of the default MIME type. +*/
  1946. static char *old_DefaultMIMEType;
  1947. /*+ The old value of the list of MIME types. +*/
  1948. static KeyPair **old_MIMETypes;
  1949. /*+ The old value of the list of hostnames and proxies. +*/
  1950. static KeyPair **old_Proxies;
  1951. /*+ The old value of the information that is needed to allow authorisation headers to be added, +*/
  1952. static KeyPair **old_ProxyAuthHost, /*+ hostname +*/
  1953.                **old_ProxyAuthUser, /*+ username +*/
  1954.                **old_ProxyAuthPass; /*+ password +*/
  1955. /*+ The old value of the SSL proxy to use. +*/
  1956. static char *old_SSLProxy;
  1957. /*+ The old value of the list of URLs not to index in the outgoing index. +*/
  1958. static KeyPair **old_DontIndexOutgoing;
  1959. /*+ The old value of the list of URLs not to index in the latest/lastime/prevtime indexes. +*/
  1960. static KeyPair **old_DontIndexLatest;
  1961. /*+ The old value of the list of URLs not to index in the monitor index. +*/
  1962. static KeyPair **old_DontIndexMonitor;
  1963. /*+ The old value of the list of URLs not to index in the host indexes. +*/
  1964. static KeyPair **old_DontIndexHost;
  1965. /*+ The old value of the list of URLs not to index. +*/
  1966. static KeyPair **old_DontIndex;
  1967. /*+ The old value of the list of protocols/hostnames and their aliases. +*/
  1968. static KeyPair **old_Aliases;
  1969. /*+ The old value of the flag to indicate that the modification time is used instead of the access time. +*/
  1970. static int old_PurgeUseMTime;
  1971. /*+ The old value of the default age for purging files. +*/
  1972. static int old_DefaultPurgeAge;
  1973. /*+ The old value of the maximum allowed size of the cache. +*/
  1974. static int old_PurgeCacheSize;
  1975. /*+ The old value of the minimum allowed free disk space. +*/
  1976. static int old_PurgeDiskFree;
  1977. /*+ The old value of the flag to indicate it the whole URL is used to choose the purge age. +*/
  1978. static int old_PurgeUseURL;
  1979. /*+ The old value of the flag to indicate if the DontGet hosts are to be purged. +*/
  1980. static int old_PurgeDontGet;
  1981. /*+ The old value of the flag to indicate if the DontCache hosts are to be purged. +*/
  1982. static int old_PurgeDontCache;
  1983. /*+ The old value of the list of hostnames and purge ages. +*/
  1984. static KeyPair **old_PurgeAges;
  1985. /*++++++++++++++++++++++++++++++++++++++
  1986.   Set default values.
  1987.   ++++++++++++++++++++++++++++++++++++++*/
  1988. static void SetDefaultValues(void)
  1989. {
  1990.  int i;
  1991.  LogLevel=Important;
  1992.  IndexLatestDays=7;
  1993.  RequestChanged=600;
  1994.  RequestChangedOnce=1;
  1995.  RequestExpired=0;
  1996.  RequestNoCache=0;
  1997.  PragmaNoCache=1;
  1998.  ConfirmRequests=0;
  1999.  /* These variables are now set at variable declaration because the
  2000.     wwwoffle program can be run without a configuration file. */
  2001.  /*
  2002.  SocketTimeout=120;
  2003.  ConnectTimeout=30;
  2004.  */
  2005.  ConnectRetry=0;
  2006.  SSLAllowPort=NULL;
  2007.  NoLasttimeIndex=0;
  2008.  IntrDownloadKeep=0;
  2009.  IntrDownloadSize=1;
  2010.  IntrDownloadPercent=80;
  2011.  TimeoutDownloadKeep=0;
  2012.  FetchStyleSheets=0;
  2013.  FetchImages=0;
  2014.  FetchFrames=0;
  2015.  FetchScripts=0;
  2016.  FetchObjects=0;
  2017.  EnableHTMLModifications=0;
  2018.  AddCacheInfo=0;
  2019.  for(i=0;i<3;i++)
  2020.    {
  2021.     AnchorModifyBegin[i]=NULL;
  2022.     AnchorModifyEnd[i]=NULL;
  2023.    }
  2024.  DisableHTMLScript=0;
  2025.  DisableHTMLBlink=0;
  2026.  DisableAnimatedGIF=0;
  2027.  LocalHost=NULL;
  2028.  LocalNet=NULL;
  2029.  AllowedConnectHosts=NULL;
  2030.  AllowedConnectUsers=NULL;
  2031.  DontCache=NULL;
  2032.  DontGet=NULL;
  2033.  DontGetReplacementURL=NULL;
  2034.  DontGetRecursive=NULL;
  2035.  DontRequestOffline=NULL;
  2036.  CensorHeader=NULL;
  2037.  RefererSelf=0;
  2038.  RefererSelfDir=0;
  2039.  FTPUserName=(char*)malloc(16); strcpy(FTPUserName,"anonymous");
  2040.  FTPPassWord=DefaultFTPPassWord();
  2041.  FTPAuthHost=NULL;
  2042.  FTPAuthUser=NULL;
  2043.  FTPAuthPass=NULL;
  2044.  DefaultMIMEType=(char*)malloc(32); strcpy(DefaultMIMEType,"text/plain");
  2045.  MIMETypes=NULL;
  2046.  Proxies=NULL;
  2047.  ProxyAuthHost=NULL;
  2048.  ProxyAuthUser=NULL;
  2049.  ProxyAuthPass=NULL;
  2050.  SSLProxy=NULL;
  2051.  DontIndexOutgoing=NULL;
  2052.  DontIndexLatest=NULL;
  2053.  DontIndexMonitor=NULL;
  2054.  DontIndexHost=NULL;
  2055.  DontIndex=NULL;
  2056.  Aliases=DefaultAliasLinks();
  2057.  PurgeUseMTime=0;
  2058.  DefaultPurgeAge=14;
  2059.  PurgeCacheSize=0;
  2060.  PurgeDiskFree=0;
  2061.  PurgeUseURL=0;
  2062.  PurgeDontGet=0;
  2063.  PurgeDontCache=0;
  2064.  PurgeAges=NULL;
  2065. }
  2066. /*++++++++++++++++++++++++++++++++++++++
  2067.   Save the old values in case the re-read of the file fails.
  2068.   ++++++++++++++++++++++++++++++++++++++*/
  2069. static void SaveOldValues(void)
  2070. {
  2071.  int i;
  2072.  old_LogLevel=LogLevel;
  2073.  old_IndexLatestDays=IndexLatestDays;
  2074.  old_RequestChanged=RequestChanged;
  2075.  old_RequestChangedOnce=RequestChangedOnce;
  2076.  old_RequestExpired=RequestExpired;
  2077.  old_RequestNoCache=RequestNoCache;
  2078.  old_PragmaNoCache=PragmaNoCache;
  2079.  old_ConfirmRequests=ConfirmRequests;
  2080.  old_SocketTimeout=SocketTimeout;
  2081.  old_ConnectTimeout=ConnectTimeout;
  2082.  old_ConnectRetry=ConnectRetry;
  2083.  old_SSLAllowPort=SSLAllowPort;
  2084.  old_NoLasttimeIndex=NoLasttimeIndex;
  2085.  old_IntrDownloadKeep=IntrDownloadKeep;
  2086.  old_IntrDownloadSize=IntrDownloadSize;
  2087.  old_IntrDownloadPercent=IntrDownloadPercent;
  2088.  old_TimeoutDownloadKeep=TimeoutDownloadKeep;
  2089.  old_FetchStyleSheets=FetchStyleSheets;
  2090.  old_FetchImages=FetchImages;
  2091.  old_FetchFrames=FetchFrames;
  2092.  old_FetchScripts=FetchScripts;
  2093.  old_FetchObjects=FetchObjects;
  2094.  old_EnableHTMLModifications=EnableHTMLModifications;
  2095.  old_AddCacheInfo=AddCacheInfo;
  2096.  for(i=0;i<3;i++)
  2097.    {
  2098.     old_AnchorModifyBegin[i]=AnchorModifyBegin[i];
  2099.     old_AnchorModifyEnd[i]=AnchorModifyEnd[i];
  2100.    }
  2101.  old_DisableHTMLScript=DisableHTMLScript;
  2102.  old_DisableHTMLBlink=DisableHTMLBlink;
  2103.  old_DisableAnimatedGIF=DisableAnimatedGIF;
  2104.  old_LocalHost=LocalHost;
  2105.  old_LocalNet=LocalNet;
  2106.  old_AllowedConnectHosts=AllowedConnectHosts;
  2107.  old_AllowedConnectUsers=AllowedConnectUsers;
  2108.  old_DontCache=DontCache;
  2109.  old_DontGet=DontGet;
  2110.  old_DontGetReplacementURL=DontGetReplacementURL;
  2111.  old_DontGetRecursive=DontGetRecursive;
  2112.  old_DontRequestOffline=DontRequestOffline;
  2113.  old_CensorHeader=CensorHeader;
  2114.  old_RefererSelf=RefererSelf;
  2115.  old_RefererSelfDir=RefererSelfDir;
  2116.  old_FTPUserName=FTPUserName;
  2117.  old_FTPPassWord=FTPPassWord;
  2118.  old_FTPAuthHost=FTPAuthHost;
  2119.  old_FTPAuthUser=FTPAuthUser;
  2120.  old_FTPAuthPass=FTPAuthPass;
  2121.  old_DefaultMIMEType=DefaultMIMEType;
  2122.  old_MIMETypes=MIMETypes;
  2123.  old_Proxies=Proxies;
  2124.  old_ProxyAuthHost=ProxyAuthHost;
  2125.  old_ProxyAuthUser=ProxyAuthUser;
  2126.  old_ProxyAuthPass=ProxyAuthPass;
  2127.  old_SSLProxy=SSLProxy;
  2128.  old_DontIndexOutgoing=DontIndexOutgoing;
  2129.  old_DontIndexLatest=DontIndexLatest;
  2130.  old_DontIndexMonitor=DontIndexMonitor;
  2131.  old_DontIndexHost=DontIndexHost;
  2132.  old_DontIndex=DontIndex;
  2133.  old_Aliases=Aliases;
  2134.  old_PurgeUseMTime=PurgeUseMTime;
  2135.  old_DefaultPurgeAge=DefaultPurgeAge;
  2136.  old_PurgeCacheSize=PurgeCacheSize;
  2137.  old_PurgeDiskFree=PurgeDiskFree;
  2138.  old_PurgeUseURL=PurgeUseURL;
  2139.  old_PurgeDontGet=PurgeDontGet;
  2140.  old_PurgeDontCache=PurgeDontCache;
  2141.  old_PurgeAges=PurgeAges;
  2142. }
  2143. /*++++++++++++++++++++++++++++++++++++++
  2144.   Restore the old values if the re-read failed.
  2145.   ++++++++++++++++++++++++++++++++++++++*/
  2146. static void RestoreOldValues(void)
  2147. {
  2148.  int i;
  2149.  LogLevel=old_LogLevel;
  2150.  IndexLatestDays=old_IndexLatestDays;
  2151.  RequestChanged=old_RequestChanged;
  2152.  RequestChangedOnce=old_RequestChangedOnce;
  2153.  RequestExpired=old_RequestExpired;
  2154.  RequestNoCache=old_RequestNoCache;
  2155.  PragmaNoCache=old_PragmaNoCache;
  2156.  ConfirmRequests=old_ConfirmRequests;
  2157.  SocketTimeout=old_SocketTimeout;
  2158.  ConnectTimeout=old_ConnectTimeout;
  2159.  ConnectRetry=old_ConnectRetry;
  2160.  if(SSLAllowPort)
  2161.     FreeKeyPairList(SSLAllowPort,0);
  2162.  SSLAllowPort=old_SSLAllowPort;
  2163.  NoLasttimeIndex=old_NoLasttimeIndex;
  2164.  IntrDownloadKeep=old_IntrDownloadKeep;
  2165.  IntrDownloadSize=old_IntrDownloadSize;
  2166.  IntrDownloadPercent=old_IntrDownloadPercent;
  2167.  TimeoutDownloadKeep=old_TimeoutDownloadKeep;
  2168.  FetchStyleSheets=old_FetchStyleSheets;
  2169.  FetchImages=old_FetchImages;
  2170.  FetchFrames=old_FetchFrames;
  2171.  FetchScripts=old_FetchScripts;
  2172.  FetchObjects=old_FetchObjects;
  2173.  EnableHTMLModifications=old_EnableHTMLModifications;
  2174.  AddCacheInfo=old_AddCacheInfo;
  2175.  for(i=0;i<3;i++)
  2176.    {
  2177.     if(AnchorModifyBegin[i])
  2178.        free(AnchorModifyBegin[i]);
  2179.     AnchorModifyBegin[i]=old_AnchorModifyBegin[i];
  2180.     if(AnchorModifyEnd[i])
  2181.        free(AnchorModifyEnd[i]);
  2182.     AnchorModifyEnd[i]=old_AnchorModifyEnd[i];
  2183.    }
  2184.  DisableHTMLScript=old_DisableHTMLScript;
  2185.  DisableHTMLBlink=old_DisableHTMLBlink;
  2186.  DisableAnimatedGIF=old_DisableAnimatedGIF;
  2187.  if(LocalHost)
  2188.     FreeKeyPairList(LocalHost,FREE_KEY_STRING);
  2189.  LocalHost=old_LocalHost;
  2190.  if(LocalNet)
  2191.     FreeKeyPairList(LocalNet,FREE_KEY_STRING);
  2192.  LocalNet=old_LocalNet;
  2193.  if(AllowedConnectHosts)
  2194.     FreeKeyPairList(AllowedConnectHosts,FREE_KEY_STRING);
  2195.  AllowedConnectHosts=old_AllowedConnectHosts;
  2196.  if(AllowedConnectUsers)
  2197.     FreeKeyPairList(AllowedConnectUsers,FREE_KEY_STRING);
  2198.  AllowedConnectUsers=old_AllowedConnectUsers;
  2199.  if(DontCache)
  2200.     FreeKeyPairList(DontCache,FREE_KEY_URLSPEC);
  2201.  DontCache=old_DontCache;
  2202.  if(DontGet)
  2203.     FreeKeyPairList(DontGet,FREE_KEY_URLSPEC|FREE_VALUE_STRING);
  2204.  DontGet=old_DontGet;
  2205.  if(DontGetReplacementURL)
  2206.     free(DontGetReplacementURL);
  2207.  DontGetReplacementURL=old_DontGetReplacementURL;
  2208.  if(DontGetRecursive)
  2209.     FreeKeyPairList(DontGetRecursive,FREE_KEY_URLSPEC);
  2210.  DontGetRecursive=old_DontGetRecursive;
  2211.  if(DontRequestOffline)
  2212.     FreeKeyPairList(DontRequestOffline,FREE_KEY_URLSPEC);
  2213.  DontRequestOffline=old_DontRequestOffline;
  2214.  if(CensorHeader)
  2215.     FreeKeyPairList(CensorHeader,FREE_KEY_STRING|FREE_VALUE_STRING);
  2216.  CensorHeader=old_CensorHeader;
  2217.  RefererSelf=old_RefererSelf;
  2218.  RefererSelfDir=old_RefererSelfDir;
  2219.  if(FTPUserName)
  2220.     free(FTPUserName);
  2221.  FTPUserName=old_FTPUserName;
  2222.  if(FTPPassWord)
  2223.     free(FTPPassWord);
  2224.  FTPPassWord=old_FTPPassWord;
  2225.  if(FTPAuthHost)
  2226.     FreeKeyPairList(FTPAuthHost,FREE_VALUE_STRING);
  2227.  FTPAuthHost=old_FTPAuthHost;
  2228.  if(FTPAuthUser)
  2229.     FreeKeyPairList(FTPAuthUser,FREE_VALUE_STRING);
  2230.  FTPAuthUser=old_FTPAuthUser;
  2231.  if(FTPAuthPass)
  2232.     FreeKeyPairList(FTPAuthPass,FREE_VALUE_STRING);
  2233.  FTPAuthPass=old_FTPAuthPass;
  2234.  if(DefaultMIMEType)
  2235.     free(DefaultMIMEType);
  2236.  DefaultMIMEType=old_DefaultMIMEType;
  2237.  if(MIMETypes)
  2238.     FreeKeyPairList(MIMETypes,FREE_KEY_STRING|FREE_VALUE_STRING);
  2239.  MIMETypes=old_MIMETypes;
  2240.  if(Proxies)
  2241.     FreeKeyPairList(Proxies,FREE_KEY_STRING|FREE_VALUE_STRING);
  2242.  Proxies=old_Proxies;
  2243.  if(ProxyAuthHost)
  2244.     FreeKeyPairList(ProxyAuthHost,FREE_VALUE_STRING);
  2245.  ProxyAuthHost=old_ProxyAuthHost;
  2246.  if(ProxyAuthUser)
  2247.     FreeKeyPairList(ProxyAuthUser,FREE_VALUE_STRING);
  2248.  ProxyAuthUser=old_ProxyAuthUser;
  2249.  if(ProxyAuthPass)
  2250.     FreeKeyPairList(ProxyAuthPass,FREE_VALUE_STRING);
  2251.  ProxyAuthPass=old_ProxyAuthPass;
  2252.  if(SSLProxy)
  2253.     free(SSLProxy);
  2254.  SSLProxy=old_SSLProxy;
  2255.  if(DontIndexOutgoing)
  2256.     FreeKeyPairList(DontIndexOutgoing,FREE_VALUE_URLSPEC);
  2257.  DontIndexOutgoing=old_DontIndexOutgoing;
  2258.  if(DontIndexLatest)
  2259.     FreeKeyPairList(DontIndexLatest,FREE_VALUE_URLSPEC);
  2260.  DontIndexLatest=old_DontIndexLatest;
  2261.  if(DontIndexMonitor)
  2262.     FreeKeyPairList(DontIndexMonitor,FREE_VALUE_URLSPEC);
  2263.  DontIndexMonitor=old_DontIndexMonitor;
  2264.  if(DontIndexHost)
  2265.     FreeKeyPairList(DontIndexHost,FREE_VALUE_URLSPEC);
  2266.  DontIndexHost=old_DontIndexHost;
  2267.  if(DontIndex)
  2268.     FreeKeyPairList(DontIndex,FREE_KEY_URLSPEC);
  2269.  DontIndex=old_DontIndex;
  2270.  if(Aliases)
  2271.     FreeKeyPairList(Aliases,FREE_KEY_URLSPEC|FREE_VALUE_URLSPEC);
  2272.  Aliases=old_Aliases;
  2273.  PurgeUseMTime=old_PurgeUseMTime;
  2274.  DefaultPurgeAge=old_DefaultPurgeAge;
  2275.  PurgeCacheSize=old_PurgeCacheSize;
  2276.  PurgeDiskFree=old_PurgeDiskFree;
  2277.  PurgeUseURL=old_PurgeUseURL;
  2278.  PurgeDontGet=old_PurgeDontGet;
  2279.  PurgeDontCache=old_PurgeDontCache;
  2280.  if(PurgeAges)
  2281.     FreeKeyPairList(PurgeAges,FREE_KEY_URLSPEC);
  2282.  PurgeAges=old_PurgeAges;
  2283. }
  2284. /*++++++++++++++++++++++++++++++++++++++
  2285.   Remove the old values if the re-read succeeded.
  2286.   ++++++++++++++++++++++++++++++++++++++*/
  2287. static void RemoveOldValues(void)
  2288. {
  2289.  int i;
  2290.  if(old_SSLAllowPort)
  2291.     FreeKeyPairList(old_SSLAllowPort,0);
  2292.  for(i=0;i<3;i++)
  2293.    {
  2294.     if(old_AnchorModifyBegin[i])
  2295.        free(old_AnchorModifyBegin[i]);
  2296.     if(old_AnchorModifyEnd[i])
  2297.        free(old_AnchorModifyEnd[i]);
  2298.    }
  2299.  if(old_LocalHost)
  2300.     FreeKeyPairList(old_LocalHost,FREE_KEY_STRING);
  2301.  if(old_LocalNet)
  2302.     FreeKeyPairList(old_LocalNet,FREE_KEY_STRING);
  2303.  if(old_AllowedConnectHosts)
  2304.     FreeKeyPairList(old_AllowedConnectHosts,FREE_KEY_STRING);
  2305.  if(old_AllowedConnectUsers)
  2306.     FreeKeyPairList(old_AllowedConnectUsers,FREE_KEY_STRING);
  2307.  if(old_DontCache)
  2308.     FreeKeyPairList(old_DontCache,FREE_KEY_URLSPEC);
  2309.  if(old_DontGet)
  2310.     FreeKeyPairList(old_DontGet,FREE_KEY_URLSPEC|FREE_VALUE_STRING);
  2311.  if(old_DontGetReplacementURL)
  2312.     free(old_DontGetReplacementURL);
  2313.  if(old_DontGetRecursive)
  2314.     FreeKeyPairList(old_DontGetRecursive,FREE_KEY_URLSPEC);
  2315.  if(old_DontRequestOffline)
  2316.     FreeKeyPairList(old_DontRequestOffline,FREE_KEY_URLSPEC);
  2317.  if(old_CensorHeader)
  2318.     FreeKeyPairList(old_CensorHeader,FREE_KEY_STRING|FREE_VALUE_STRING);
  2319.  if(old_FTPUserName)
  2320.     free(old_FTPUserName);
  2321.  if(old_FTPPassWord)
  2322.     free(old_FTPPassWord);
  2323.  if(old_FTPAuthHost)
  2324.     FreeKeyPairList(old_FTPAuthHost,FREE_VALUE_STRING);
  2325.  if(old_FTPAuthUser)
  2326.     FreeKeyPairList(old_FTPAuthUser,FREE_VALUE_STRING);
  2327.  if(old_FTPAuthPass)
  2328.     FreeKeyPairList(old_FTPAuthPass,FREE_VALUE_STRING);
  2329.  if(old_DefaultMIMEType)
  2330.     free(old_DefaultMIMEType);
  2331.  if(old_MIMETypes)
  2332.     FreeKeyPairList(old_MIMETypes,FREE_KEY_STRING|FREE_VALUE_STRING);
  2333.  if(old_Proxies)
  2334.     FreeKeyPairList(old_Proxies,FREE_KEY_URLSPEC|FREE_VALUE_STRING);
  2335.  if(old_ProxyAuthHost)
  2336.     FreeKeyPairList(old_ProxyAuthHost,FREE_VALUE_STRING);
  2337.  if(old_ProxyAuthUser)
  2338.     FreeKeyPairList(old_ProxyAuthUser,FREE_VALUE_STRING);
  2339.  if(old_ProxyAuthPass)
  2340.     FreeKeyPairList(old_ProxyAuthPass,FREE_VALUE_STRING);
  2341.  if(old_SSLProxy)
  2342.     free(old_SSLProxy);
  2343.  if(old_DontIndexOutgoing)
  2344.     FreeKeyPairList(old_DontIndexOutgoing,FREE_VALUE_URLSPEC);
  2345.  if(old_DontIndexLatest)
  2346.     FreeKeyPairList(old_DontIndexLatest,FREE_VALUE_URLSPEC);
  2347.  if(old_DontIndexMonitor)
  2348.     FreeKeyPairList(old_DontIndexMonitor,FREE_VALUE_URLSPEC);
  2349.  if(old_DontIndexHost)
  2350.     FreeKeyPairList(old_DontIndexHost,FREE_VALUE_URLSPEC);
  2351.  if(old_DontIndex)
  2352.     FreeKeyPairList(old_DontIndex,FREE_KEY_URLSPEC);
  2353.  if(old_Aliases)
  2354.     FreeKeyPairList(old_Aliases,FREE_KEY_URLSPEC|FREE_VALUE_URLSPEC);
  2355.  if(old_PurgeAges)
  2356.     FreeKeyPairList(old_PurgeAges,FREE_KEY_URLSPEC);
  2357. }
  2358. /*++++++++++++++++++++++++++++++++++++++
  2359.   Free a KeyPair list.
  2360.   KeyPair **list The list to free.
  2361.   int freewhat A bitwise OR of FREE_KEY_STRING or FREE_KEY_URLSPEC and FREE_VALUE_STRING or FREE_VALUE_URLSPEC.
  2362.   ++++++++++++++++++++++++++++++++++++++*/
  2363. static void FreeKeyPairList(KeyPair **list,int freewhat)
  2364. {
  2365.  KeyPair **p;
  2366.  for(p=list;(*p)!=&KeyPairEnd;p++)
  2367.    {
  2368.     if(freewhat&FREE_KEY_STRING && (*p)->key.string)
  2369.        free((*p)->key.string);
  2370.     if(freewhat&FREE_KEY_URLSPEC && (*p)->key.urlspec)
  2371.       {
  2372.        if((*p)->key.urlspec->proto)
  2373.           free((*p)->key.urlspec->proto);
  2374.        if((*p)->key.urlspec->host)
  2375.           free((*p)->key.urlspec->host);
  2376.        if((*p)->key.urlspec->path)
  2377.           free((*p)->key.urlspec->path);
  2378.        if((*p)->key.urlspec->args && *(*p)->key.urlspec->args)
  2379.           free((*p)->key.urlspec->args);
  2380.        free((*p)->key.urlspec);
  2381.       }
  2382.     if(freewhat&FREE_VALUE_STRING && (*p)->value.string)
  2383.        free((*p)->value.string);
  2384.     if(freewhat&FREE_VALUE_URLSPEC && (*p)->value.urlspec)
  2385.       {
  2386.        if((*p)->value.urlspec->proto)
  2387.           free((*p)->value.urlspec->proto);
  2388.        if((*p)->value.urlspec->host)
  2389.           free((*p)->value.urlspec->host);
  2390.        if((*p)->value.urlspec->path)
  2391.           free((*p)->value.urlspec->path);
  2392.        if((*p)->value.urlspec->args && *(*p)->value.urlspec->args)
  2393.           free((*p)->value.urlspec->args);
  2394.        free((*p)->value.urlspec);
  2395.       }
  2396.     free(*p);
  2397.    }
  2398.  free(list);
  2399. }