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

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /*
  19.  * mkautocf.c: Proxy auto-config parser and evaluator
  20.  * Ari Luotonen
  21.  *
  22.  * Updated and Documented by Judson Valeski 11/19/1997
  23.  */
  24. #include "mkutils.h"    /* LF */
  25. #include "mkpadpac.h"
  26. #include <time.h>
  27. #include "mkautocf.h"
  28. #include "xp_mem.h"     /* XP_NEW_ZAP() */
  29. #ifndef XP_MAC
  30. #include <sys/types.h>
  31. #endif
  32. #include "libi18n.h"
  33. #include "mkstream.h"
  34. #include "mkgeturl.h"
  35. #include "cvextcon.h"
  36. #include "mkformat.h"
  37. #include "mime.h"
  38. #include "cvactive.h"
  39. #include "gui.h"
  40. #include "msgcom.h"
  41. #include "prefapi.h"
  42. #define WANT_ENUM_STRING_IDS
  43. #include "allxpstr.h"
  44. #undef WANT_ENUM_STRING_IDS
  45. #include "xp_reg.h"
  46.  
  47. #ifndef NSPR20
  48. #if defined(XP_UNIX) || defined(XP_WIN32)
  49. #include "prnetdb.h"
  50. #else
  51. #define PRHostEnt struct hostent
  52. #endif
  53. #else
  54. #include "prnetdb.h"
  55. #endif
  56.  
  57. #include "net.h"
  58. #include "libmocha.h"
  59. #include "jsapi.h"
  60. #include "jscompat.h"
  61. #include "jspubtd.h"
  62.  
  63. /* for XP_GetString() */
  64. #include "xpgetstr.h"
  65. #ifdef NOT
  66. extern int XP_BAD_KEYWORD_IN_PROXY_AUTOCFG;
  67. extern int XP_RETRY_AGAIN_PROXY;
  68. extern int XP_RETRY_AGAIN_SOCKS;
  69. extern int XP_RETRY_AGAIN_PROXY_OR_SOCKS;
  70. extern int XP_PROXY_UNAVAILABLE_TRY_AGAIN;
  71. extern int XP_ALL_PROXIES_DOWN_TRY_AGAIN;
  72. extern int XP_ALL_SOCKS_DOWN;
  73. extern int XP_ALL_DOWN_MIX;
  74. extern int XP_OVERRIDE_PROXY;
  75. extern int XP_OVERRIDE_SOCKS;
  76. extern int XP_OVERRIDE_MIX;
  77. extern int XP_STILL_OVERRIDE_PROXY;
  78. extern int XP_STILL_OVERRIDE_SOCKS;
  79. extern int XP_STILL_OVERRIDE_MIX;
  80. extern int XP_NO_CONFIG_RECIEVED;
  81. extern int XP_NO_CONFIG_RECEIVED_NO_FAILOVER;
  82. extern int XP_EMPTY_CONFIG_USE_PREV;
  83. extern int XP_BAD_CONFIG_USE_PREV;
  84. extern int XP_BAD_CONFIG_IGNORED;
  85. extern int XP_BAD_TYPE_USE_PREV;
  86. extern int XP_BAD_TYPE_CONFIG_IGNORED;
  87. extern int XP_CONF_LOAD_FAILED_IGNORED;
  88. extern int XP_CONF_LOAD_FAILED_NO_FAILOVER;
  89. extern int XP_CONF_LOAD_FAILED_USE_PREV;
  90. extern int XP_EVEN_SAVED_IS_BAD;
  91. extern int XP_CONFIG_LOAD_ABORTED;
  92. extern int XP_CONFIG_BLAST_WARNING;
  93. extern int XP_RECEIVING_PROXY_AUTOCFG;
  94. extern int XP_AUTOADMIN_MISSING;
  95. #endif
  96.  
  97. #define PACF_MIN_RETRY_AFTER    300
  98. #define PACF_MIN_RETRY_ASK       25
  99. #define PACF_AUTO_RETRY_AFTER  1800
  100. #define PACF_DIRECT_INTERVAL   1200
  101. #define PACF_RETRY_OK_AFTER      30
  102.  
  103. /* Types of retrievals: retrieve directly, thru a proxy, or using socks. */
  104. typedef enum _PACF_Type {
  105.     PACF_TYPE_INVALID = 0,
  106.     PACF_TYPE_DIRECT,
  107.     PACF_TYPE_PROXY,
  108.     PACF_TYPE_SOCKS
  109. } PACF_Type;
  110.  
  111. /* Info about the proxy/socks server hostname/IP address and port. 
  112.  * These nodes are kept in a list so we don't have to parse the pac file
  113.  * every time to gather proxy/socks info. */
  114. typedef struct _PACF_Node {
  115.     PACF_Type   type;   /* direct | proxy | socks */
  116.     char *      addr;
  117.     u_long      socks_addr;
  118.     short       socks_port;
  119.     int         retries;
  120.     time_t      retrying;
  121.     time_t      last_try;
  122.     time_t      down_since;
  123. } PACF_Node;
  124.  
  125. /* Private object for the proxy config loader stream. */
  126. typedef struct _PACF_Object {
  127.    MWContext *  context;
  128.    int          flag;
  129. } PACF_Object;
  130.  
  131. /* A struct for holding queued state.
  132.  *
  133.  * The state is saved when NET_GetURL() is called for the first time,
  134.  * and the proxy autoconfig retrieve has to be started (and finished)
  135.  * before the first actual document can be loaded.
  136.  *
  137.  * A pre-exit function for the proxy autoconfig URL restarts the
  138.  * original URL retrieve by calling NET_GetURL() again with the
  139.  * same parameters. */
  140. typedef struct _PACF_QueuedState {
  141.     URL_Struct *        URL_s;
  142.     FO_Present_Types    output_format;
  143.     MWContext *         window_id;
  144.     Net_GetUrlExitFunc* exit_routine;
  145. } PACF_QueuedState;
  146.  
  147. typedef enum {
  148.     PACF_SECONDARY_URL,
  149.     PACF_BINDINGS
  150. } pc_slot;
  151.  
  152. /* Declared in mkgeturl.c. NET_GetURL uses these variables to determine
  153.  * whether or not the pac file has been loaded. */
  154. extern XP_Bool NET_GlobalAcLoaded;
  155. extern XP_Bool NET_ProxyAcLoaded;
  156.  
  157. /* Private proxy auto-config variables */
  158. #ifdef MOCHA
  159. PRIVATE Bool    pacf_do_failover  = TRUE;
  160. PRIVATE Bool    pacf_loading      = FALSE;
  161. PRIVATE Bool    pacf_ok           = FALSE;
  162. PRIVATE char *  pacf_url          = NULL;
  163. PRIVATE char *  pacf_src_buf      = NULL;
  164. PRIVATE int     pacf_src_len      = 0;
  165. PRIVATE XP_List*pacf_all_nodes    = NULL;
  166. PRIVATE time_t  pacf_direct_until = (time_t)0;
  167. PRIVATE int     pacf_direct_cnt   = 0;
  168. PRIVATE PACF_QueuedState *queued_state = NULL;
  169. PRIVATE XP_List*pacf_bad_keywords = NULL;
  170.  
  171. PRIVATE Bool    pacf_find_proxy_undefined = FALSE;
  172.  
  173. /* Javascript stuff. A javascript context does the interpretation and
  174.  * compilation of the pac file. */
  175. PRIVATE JSPropertySpec pc_props[] = {
  176.     {"secondary", PACF_SECONDARY_URL},
  177.     {"bindings",  PACF_BINDINGS},
  178.     {0}
  179. };
  180.  
  181. PRIVATE JSClass pc_class = {
  182.     "ProxyConfig", 0,
  183.     JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
  184.     JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
  185. };
  186.  
  187. /* PRIVATE JSPropertySpec no_props[1] = { { NULL } }; */
  188. PRIVATE JSObject *proxyConfig = NULL;
  189. PRIVATE JSObject *globalConfig = NULL;
  190. PRIVATE JSContext *configContext = NULL;
  191.  
  192. /* The javascript methods */
  193. MODULE_PRIVATE JSBool PR_CALLBACK proxy_weekdayRange(JSContext *mc, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  194. MODULE_PRIVATE JSBool PR_CALLBACK proxy_dateRange(JSContext *mc, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  195. MODULE_PRIVATE JSBool PR_CALLBACK proxy_timeRange(JSContext *mc, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  196. MODULE_PRIVATE JSBool PR_CALLBACK proxy_isPlainHostName(JSContext *mc, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  197. MODULE_PRIVATE JSBool PR_CALLBACK proxy_dnsDomainLevels(JSContext *mc, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  198. MODULE_PRIVATE JSBool PR_CALLBACK proxy_dnsDomainIs(JSContext *mc, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  199. MODULE_PRIVATE JSBool PR_CALLBACK proxy_localHostOrDomainIs(JSContext *mc, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  200. MODULE_PRIVATE JSBool PR_CALLBACK proxy_isResolvable(JSContext *mc, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  201. MODULE_PRIVATE JSBool PR_CALLBACK proxy_dnsResolve(JSContext *mc, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  202. MODULE_PRIVATE JSBool PR_CALLBACK proxy_isInNet(JSContext *mc, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  203. MODULE_PRIVATE JSBool PR_CALLBACK proxy_myIpAddress(JSContext *mc, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  204. MODULE_PRIVATE JSBool PR_CALLBACK proxy_regExpMatch(JSContext *mc, JSObject *obj, unsigned int argc, jsval *argv, jsval *rval);
  205.  
  206. PRIVATE JSFunctionSpec pc_methods[] = {
  207.     { "weekdayRange",        proxy_weekdayRange,        3},
  208.     { "dateRange",           proxy_dateRange,           7},
  209.     { "timeRange",           proxy_timeRange,           7},
  210.     { "isPlainHostName",     proxy_isPlainHostName,     1},
  211.     { "dnsDomainLevels",     proxy_dnsDomainLevels,     1},
  212.     { "dnsDomainIs",         proxy_dnsDomainIs,         2},
  213.     { "localHostOrDomainIs", proxy_localHostOrDomainIs, 2},
  214.     { "isResolvable",        proxy_isResolvable,        1},
  215.     { "dnsResolve",          proxy_dnsResolve,          1},
  216.     { "isInNet",             proxy_isInNet,             3},
  217.     { "myIpAddress",         proxy_myIpAddress,         0},
  218.     { "regExpMatch",         proxy_regExpMatch,         2},
  219.     { "shExpMatch",          proxy_regExpMatch,         2},
  220.     { NULL,                  NULL,                      0}
  221. };
  222.  
  223. PRIVATE char *mkMethodString( int method ) {
  224.   char *mstr= NULL;
  225.  
  226.   switch ( method ) {
  227.       case  URL_GET_METHOD: 
  228.         mstr = XP_STRDUP("GET");
  229.         break;
  230.       case URL_POST_METHOD:
  231.         mstr = XP_STRDUP("POST");
  232.         break;
  233.       case  URL_HEAD_METHOD:
  234.         mstr = XP_STRDUP("HEAD");
  235.         break;
  236.       case  URL_PUT_METHOD:
  237.         mstr = XP_STRDUP("PUT");
  238.         break;
  239.       case  URL_DELETE_METHOD:
  240.         mstr = XP_STRDUP("DELETE");
  241.         break;
  242.       case  URL_MKDIR_METHOD :
  243.         mstr = XP_STRDUP("MKDIR");
  244.         break;
  245.       case  URL_MOVE_METHOD:
  246.         mstr = XP_STRDUP("MOVE");
  247.         break;
  248.       case  URL_INDEX_METHOD:
  249.         mstr = XP_STRDUP("INDEX");
  250.         break;
  251.       case  URL_GETPROPERTIES_METHOD:
  252.         mstr = XP_STRDUP("GETPROPERTIES");
  253.         break;
  254.   }
  255.   return mstr;
  256. }
  257.  
  258. PRIVATE char *msg2(char *fmt, char *prm) {
  259.     char *msg = (char *)XP_ALLOC(XP_STRLEN(fmt) + 100 +
  260.                  (prm ? XP_STRLEN(prm) : 0));
  261.     if (msg)
  262.     XP_SPRINTF(msg, fmt, prm ? prm : "-");
  263.  
  264.     return msg;
  265. }
  266.  
  267. PRIVATE Bool confirm2(MWContext *context, char *fmt, char *prm) {
  268.     Bool rv = TRUE;
  269.     char *msg = msg2(fmt, prm);
  270.     if (msg) {
  271.     rv = FE_Confirm(context, msg);
  272.     XP_FREE(msg);
  273.     }
  274.     return rv;
  275. }
  276.  
  277. PRIVATE void alert2(MWContext *context, char *fmt, char *prm) {
  278.     char *msg = msg2(fmt, prm);
  279.     if (msg) {
  280.     FE_Alert(context, msg);
  281.     XP_FREE(msg);
  282.     }
  283. }
  284.  
  285. /* Returns a node representing a proxy/SOCKS server address or
  286.  * direct access, and guarantees to return the same node if one
  287.  * was already created for that address. */
  288. PRIVATE PACF_Node *lookup_create_node(PACF_Type type, char *addr) {
  289.     if (!pacf_all_nodes)
  290.     pacf_all_nodes = XP_ListNew();
  291.  
  292.     /* Truncate at 64 characters -- gethostbyname() is evil */
  293.     if (addr && XP_STRLEN(addr) > 64)
  294.     addr[64] = '\0';
  295.  
  296.     if (!type || (!addr && (type == PACF_TYPE_PROXY ||
  297.                 type == PACF_TYPE_SOCKS)))
  298.       {
  299.       return NULL;
  300.       }
  301.     else
  302.       {
  303.       XP_List *cur = pacf_all_nodes;
  304.       PACF_Node *node;
  305.  
  306.       while ((node = (PACF_Node *)XP_ListNextObject(cur)) != NULL) {
  307.           if (node->type == type &&
  308.           ((!node->addr && !addr) ||
  309.            ( node->addr &&  addr  && !strcmp(node->addr, addr))))
  310.         {
  311.             return node;
  312.         }
  313.       }
  314.  
  315.       node = XP_NEW_ZAP(PACF_Node);
  316.       if (node) {
  317.           node->type = type;
  318.           node->addr = XP_STRDUP(addr);
  319.  
  320.           XP_ListAddObject(pacf_all_nodes, node);
  321.       }
  322.  
  323.       return node;
  324.       }
  325. }
  326.  
  327. /* Called by netlib when it notices that a proxy is down. */
  328. PRIVATE PACF_Node * pacf_proxy_is_down(MWContext *context,
  329.                        char *proxy_addr,
  330.                        u_long socks_addr,
  331.                        short socks_port) {
  332.     XP_List *cur = pacf_all_nodes;
  333.     PACF_Node *node;
  334.  
  335.     while ((node = (PACF_Node *)XP_ListNextObject(cur)) != NULL) {
  336.     if ((proxy_addr && node->addr && !XP_STRCMP(node->addr, proxy_addr)) ||
  337.         (socks_addr &&
  338.          node->socks_addr == socks_addr &&
  339.          node->socks_port == socks_port))
  340.       {
  341.           time_t now = time(NULL);
  342.  
  343.           if (!node->down_since) {
  344.  
  345.           node->down_since = now;
  346.           }
  347.           node->last_try = now;
  348.           node->retrying = (time_t)0;
  349.           return node;
  350.       }
  351.     }
  352.     return NULL;
  353. }
  354.  
  355. PRIVATE Bool fill_return_values(PACF_Type   type,
  356.                 PACF_Node * node,
  357.                 char **     ret_proxy_addr,
  358.                 u_long *    ret_socks_addr,
  359.                 short *     ret_socks_port) {
  360.     *ret_proxy_addr = NULL;
  361.     *ret_socks_addr = 0;
  362.     *ret_socks_port = 0;
  363.  
  364.     if(!node)
  365.         return FALSE;
  366.  
  367.     if (type == PACF_TYPE_PROXY) {
  368.     *ret_proxy_addr = node->addr;
  369.     }
  370.     else if (!node->socks_addr) {
  371.     char *p, *host = NULL;
  372.  
  373.     StrAllocCopy(host, node->addr);
  374.     p = XP_STRCHR(host, ':');
  375.     if (p) {
  376.         *p++ = '\0';
  377.         node->socks_port = (short)atoi(p);
  378.     }
  379.     else {
  380.         node->socks_port = 1080;
  381.     }
  382.  
  383.     if (isdigit(*host)) {
  384.         /*
  385.          * Some systems return a number instead of a struct
  386.          */
  387.         node->socks_addr = inet_addr(host);
  388.     }
  389.     else {
  390. #ifdef NSPR20
  391.         PRStatus rv;
  392.         PRHostEnt  *hp;
  393.         PRHostEnt  hpbuf;
  394.         char dbbuf[PR_NETDB_BUF_SIZE];
  395. #else
  396.         struct hostent  *hp;
  397. #if defined(XP_UNIX) || defined(XP_WIN32) 
  398.         struct hostent hpbuf;
  399.         char dbbuf[PR_NETDB_BUF_SIZE];
  400. #endif
  401. #endif /* NSPR20 */
  402.  
  403.         NET_InGetHostByName++; /* global semaphore */
  404. #ifdef NSPR20
  405.         rv = PR_GetHostByName(host, dbbuf, sizeof(dbbuf),  &hpbuf);
  406.         hp = (rv == PR_SUCCESS ? &hpbuf : NULL);
  407. #elif defined(XP_UNIX) || defined(XP_WIN32)
  408.         hp = PR_gethostbyname(host, &hpbuf, dbbuf, sizeof(dbbuf), 0); 
  409. #else
  410.         hp = gethostbyname(host); 
  411. #endif
  412.         NET_InGetHostByName--; /* global semaphore */
  413.  
  414.         if (!hp)
  415.         return FALSE;  /* Fail? */
  416.  
  417.         XP_MEMCPY(&node->socks_addr, hp->h_addr, hp->h_length);
  418.     }
  419.     }
  420.  
  421.     *ret_socks_addr = node->socks_addr;
  422.     *ret_socks_port = node->socks_port;
  423.     return TRUE;
  424. }
  425.  
  426. #endif /* MOCHA */
  427.  
  428. /* NET_SetNoProxyFailover
  429.  * Sets a flag that indicates that proxy failover should not
  430.  * be done.  This is used by the Enterprise Kit code, where
  431.  * the customer might configure the client to use specific
  432.  * proxies.  In these cases, failover can cause different
  433.  * proxies, or no proxies to be used. */
  434. PUBLIC void
  435. NET_SetNoProxyFailover(void) {
  436. #ifdef MOCHA
  437.   pacf_do_failover = FALSE;
  438. #endif
  439. }
  440.  
  441. PUBLIC XP_Bool
  442. NET_LoadingPac(void) {
  443.     return pacf_loading;
  444. }
  445.  
  446. #ifdef MOZILLA_CLIENT
  447. /*
  448.  * NET_GetNoProxyFailover
  449.  */
  450. MODULE_PRIVATE Bool
  451. NET_GetNoProxyFailover(void) {
  452.   return ( pacf_do_failover == FALSE );
  453. }
  454. #endif /* MOZILLA_CLIENT */
  455.  
  456. /* Called by netlib to get a single string of "host:port" format,
  457.  * given the string of possibilities returned by the Mocha script.
  458.  *
  459.  * This function will return an address to a proxy that is (to its
  460.  * knowledge) up and running.  Netlib can later inform this module
  461.  * using the function pacf_proxy_is_down() that a proxy is down
  462.  * and should not be called for a few minutes.
  463.  *
  464.  * Returns FALSE if everything has failed, and an error should be
  465.  * displayed to the user.
  466.  *
  467.  * Returns TRUE if there is hope.
  468.  * If *ret is NULL, a direct connection should be attempted.
  469.  * If *ret is not null, it is the proxy address to use. */
  470. MODULE_PRIVATE Bool
  471. pacf_get_proxy_addr(MWContext *context, char *list, char **ret_proxy_addr,
  472.             u_long *ret_socks_addr, short *ret_socks_port) {
  473. #ifdef MOCHA
  474.     Bool rv = FALSE;
  475.     char *my_copy, *cur, *p, *addr;
  476.     PACF_Type type = PACF_TYPE_INVALID;
  477.     PACF_Node *node;
  478.     PACF_Node *sm_ptr = NULL;
  479.     PACF_Node *went_down = NULL;
  480.     time_t now = time(NULL);
  481.     time_t smallest = (time_t)0;
  482.     int proxy_cnt = 0;
  483.     int socks_cnt = 0;
  484.     int retry_now = 0;
  485.  
  486.     if (!list || !*list || !ret_proxy_addr || !ret_socks_addr || !ret_socks_port)
  487.     return FALSE;
  488.  
  489.     if (*ret_proxy_addr || *ret_socks_addr) {
  490.     /*
  491.      * We get called here because this proxy/SOCKS server was down.
  492.      */
  493.     went_down = pacf_proxy_is_down(context, *ret_proxy_addr,
  494.                        *ret_socks_addr, *ret_socks_port);
  495.     }
  496.  
  497.     *ret_proxy_addr = NULL;
  498.     *ret_socks_addr = 0;
  499.     *ret_socks_port = 0;
  500.  
  501.     cur = my_copy = XP_STRDUP(list);
  502.  
  503.     TRACEMSG(("Getting proxy addr from config list: %s", list));
  504.  
  505.     do {
  506.         p = XP_STRCHR(cur, ';');
  507.         if (p) {
  508.             do {
  509.                 *p++ = '\0';
  510.         } while (*p && XP_IS_SPACE(*p));
  511.         }
  512.  
  513.         for (addr=cur; *addr && !XP_IS_SPACE(*addr); addr++)
  514.             ;
  515.         if (*addr) {
  516.             do {
  517.             *addr++ = '\0';
  518.             } while (*addr &&  XP_IS_SPACE(*addr));
  519.         }
  520.  
  521.         type = ((!strcasecomp(cur, "DIRECT")) ? PACF_TYPE_DIRECT  :
  522.             (!strcasecomp(cur, "PROXY"))  ? PACF_TYPE_PROXY   :
  523.             (!strcasecomp(cur, "SOCKS"))  ? PACF_TYPE_SOCKS   :
  524.                             PACF_TYPE_INVALID );
  525.  
  526.         if (type == PACF_TYPE_DIRECT)           /* don't use a proxy */
  527.           {
  528.               rv = TRUE;
  529.               break;                            /* done */
  530.           }
  531.         else if (type ==  PACF_TYPE_PROXY ||    /* use a proxy or... */       
  532.              type ==  PACF_TYPE_SOCKS )     /* use SOCKS */
  533.           {
  534.               if (type == PACF_TYPE_PROXY)
  535.               proxy_cnt++;
  536.               else
  537.               socks_cnt++;
  538.  
  539.           node = lookup_create_node(type, addr);
  540.               if (*addr && node) {
  541.               if (node->down_since && node->retrying &&
  542.                   now - node->retrying > PACF_RETRY_OK_AFTER)
  543.                 {
  544.                 node->down_since = node->retrying = (time_t)0;
  545.                 }
  546.  
  547.               if (!node->down_since)
  548.                 {
  549.                 if (fill_return_values(type, node,
  550.                                ret_proxy_addr,
  551.                                ret_socks_addr,
  552.                                ret_socks_port))
  553.                   {
  554.                       rv = TRUE;
  555.                       break;
  556.                   }
  557.                 }
  558.               else if (now - node->last_try >
  559.                    (node->retries + 1) * PACF_AUTO_RETRY_AFTER)
  560.                 {
  561.                 node->retries++;
  562.                 if (fill_return_values(type, node,
  563.                                ret_proxy_addr,
  564.                                ret_socks_addr,
  565.                                ret_socks_port))
  566.                   {
  567.                       node->retrying = now;
  568.                       rv = TRUE;
  569.                       break;
  570.                   }
  571.                 }
  572.               else if (node != went_down &&
  573.                    (!smallest || smallest > node->last_try))
  574.                 {
  575.                 smallest = node->last_try;
  576.                 sm_ptr = node;
  577.                 }
  578.               }
  579.           }
  580.         else                                    /* invalid entry */
  581.           {
  582.             char *key = NULL;
  583.  
  584.             if (!pacf_bad_keywords)
  585.             {
  586.                 pacf_bad_keywords = XP_ListNew();
  587.             }
  588.             else
  589.             {
  590.                 XP_List *ptr = pacf_bad_keywords;
  591.  
  592.                 while ((key = (char *)XP_ListNextObject(ptr)) != NULL) {
  593.                 if (!strcmp(key, cur))
  594.                     break;
  595.                 }
  596.             }
  597.  
  598.               if (!key && XP_ListCount(pacf_bad_keywords) < 3)
  599.             {
  600.                 key = XP_STRDUP(cur);
  601.                 XP_ListAddObject(pacf_bad_keywords, key);
  602.                 alert2(context, XP_GetString(XP_BAD_KEYWORD_IN_PROXY_AUTOCFG), cur);
  603.             }
  604.           }
  605.  
  606.         cur = p;
  607.  
  608.         } while (cur && *cur);
  609.  
  610.     XP_FREE(my_copy);
  611.  
  612.     if (rv)
  613.       return TRUE;
  614.  
  615.     /* If we didn't return just above here, and we're using a pad pac file,
  616.      * something went wrong with it so disable it for this session and return
  617.      * true so we go direct. */
  618.     if(NET_UsingPadPac()) {
  619.         net_UsePadPac(FALSE);
  620.         return TRUE;
  621.     }
  622.  
  623.     if (pacf_do_failover && pacf_direct_until) {
  624.       if (now < pacf_direct_until)
  625.         {
  626.         return TRUE;
  627.         }
  628.       else if (!FE_Confirm(context,
  629.                    !socks_cnt ? XP_GetString(XP_RETRY_AGAIN_PROXY) :
  630.                    !proxy_cnt ? XP_GetString(XP_RETRY_AGAIN_SOCKS) : XP_GetString(XP_RETRY_AGAIN_PROXY_OR_SOCKS)))
  631.         {
  632.         pacf_direct_until = now + (++pacf_direct_cnt) * PACF_DIRECT_INTERVAL;
  633.         return TRUE;
  634.         }
  635.       else
  636.         {
  637.         pacf_direct_until = (time_t)0;
  638.         retry_now = 1;
  639.         }
  640.     }
  641.  
  642.     if (smallest &&
  643.     (retry_now ||
  644.      now - smallest > PACF_MIN_RETRY_AFTER ||
  645.      (sm_ptr && !sm_ptr->retrying &&
  646.       now - smallest > PACF_MIN_RETRY_ASK &&
  647.       confirm2(context,
  648.            (!socks_cnt && proxy_cnt==1 ? XP_GetString(XP_PROXY_UNAVAILABLE_TRY_AGAIN) :
  649.             !socks_cnt && proxy_cnt >1 ? XP_GetString(XP_ALL_PROXIES_DOWN_TRY_AGAIN) :
  650.             !proxy_cnt                 ? XP_GetString(XP_ALL_SOCKS_DOWN) :
  651.                          XP_GetString(XP_ALL_DOWN_MIX)),
  652.            sm_ptr->addr))) &&
  653.     fill_return_values(type, sm_ptr,
  654.                ret_proxy_addr, ret_socks_addr, ret_socks_port))
  655.       {
  656.       sm_ptr->retrying = now;
  657.       sm_ptr->retries++;
  658.       return TRUE;
  659.       }
  660.     else if (pacf_do_failover && FE_Confirm(context,
  661.             !pacf_direct_cnt ?
  662.             (!socks_cnt ? XP_GetString(XP_OVERRIDE_PROXY) :
  663.              !proxy_cnt ? XP_GetString(XP_OVERRIDE_SOCKS) : XP_GetString(XP_OVERRIDE_MIX)) :
  664.             (!socks_cnt ? XP_GetString(XP_STILL_OVERRIDE_PROXY) :
  665.              !proxy_cnt ? XP_GetString(XP_STILL_OVERRIDE_SOCKS) : XP_GetString(XP_STILL_OVERRIDE_SOCKS))))
  666.       {
  667.       pacf_direct_until = now + (++pacf_direct_cnt) * PACF_DIRECT_INTERVAL;
  668.       return TRUE;
  669.       }
  670.     else
  671.       {
  672.       return FALSE;
  673.       }
  674. #else
  675.     return FALSE;
  676. #endif /* MOCHA */
  677. }
  678.  
  679. #ifdef MOCHA
  680.  
  681.  
  682. /* Saves out the proxy autoconfig file to disk, in case the server
  683.  * is down the next time.
  684.  *
  685.  * Returns 0 on success, -1 on failure. */
  686. PRIVATE int pacf_save_config(void) {
  687.     XP_File fp;
  688.     int32 len = 0;
  689.  
  690.     if (!pacf_do_failover || !pacf_src_buf || !*pacf_src_buf || pacf_src_len <= 0)
  691.     return -1;
  692.  
  693.     if(!(fp = XP_FileOpen("", xpProxyConfig, XP_FILE_WRITE)))
  694.     return -1;
  695.  
  696.     len = XP_FileWrite(pacf_src_buf, pacf_src_len, fp);
  697.     XP_FileClose(fp);
  698.     if (len != pacf_src_len)
  699.         return -1;
  700.  
  701.     return 0;
  702. }
  703.  
  704. /* Reads the proxy autoconfig file from disk.
  705.  * This is called if the config server is not responding.
  706.  *
  707.  * returns 0 on success -1 on failure. */
  708. PRIVATE int pacf_read_config(void) {
  709.     XP_StatStruct st;
  710.     XP_File fp;
  711.  
  712.     if (XP_Stat("", &st, xpProxyConfig) == -1)
  713.     return -1;
  714.  
  715.     if (!(fp = XP_FileOpen("", xpProxyConfig, XP_FILE_READ)))
  716.     return -1;
  717.  
  718.     pacf_src_len = st.st_size;
  719.     pacf_src_buf = (char *)XP_ALLOC(pacf_src_len + 1);
  720.     if (!pacf_src_buf) {
  721.     XP_FileClose(fp);
  722.     pacf_src_len = 0;
  723.     return -1;
  724.     }
  725.  
  726.     if ((pacf_src_len = XP_FileRead(pacf_src_buf, pacf_src_len, fp)) > 0)
  727.       {
  728.       pacf_src_buf[pacf_src_len] = '\0';
  729.       }
  730.     else
  731.       {
  732.       XP_FREE(pacf_src_buf);
  733.       pacf_src_buf = NULL;
  734.       pacf_src_len = 0;
  735.       }
  736.  
  737.     XP_FileClose(fp);
  738.  
  739.     return 0;
  740. }
  741.  
  742. /* Private stream object methods for receiving the proxy autoconfig file. */
  743. PRIVATE int pacf_write(NET_StreamClass *stream, CONST char *buf, int32 len) {
  744.     PACF_Object *obj=stream->data_object;    
  745.     if (len > 0) {
  746.     if (!pacf_src_buf)
  747.         pacf_src_buf = (char*)XP_ALLOC(len + 1);
  748.     else
  749.         pacf_src_buf = (char*)XP_REALLOC(pacf_src_buf,
  750.                          pacf_src_len + len + 1);
  751.  
  752.     if (!pacf_src_buf) {    /* Out of memory */
  753.         pacf_src_len = 0;
  754.         return MK_DATA_LOADED;
  755.     }
  756.  
  757.     XP_MEMCPY(pacf_src_buf + pacf_src_len, buf, len);
  758.     pacf_src_len += len;
  759.     pacf_src_buf[pacf_src_len] = '\0';
  760.     }
  761.     return MK_DATA_LOADED;
  762. }
  763.  
  764. PRIVATE unsigned int pacf_write_ready(NET_StreamClass *stream) {    
  765.     return MAX_WRITE_READY;
  766. }
  767.  
  768. PRIVATE void pacf_complete(NET_StreamClass *stream) {
  769.     PACF_Object *obj=stream->data_object;
  770.     jsval result;
  771.     XP_StatStruct st;
  772.     JSBool ok;    
  773.  
  774. retry:
  775.     if (!obj->flag || obj->flag == 2) {
  776.     pacf_loading = FALSE;
  777.  
  778.  
  779.     /*  JONM -- Check me over please!
  780.       proxyConfig =
  781.       MOCHA_DefineNewObject(decoder->js_context, decoder->window_object,
  782.                 "ProxyConfig", &pc_class, NULL, NULL, 0,
  783.                 pc_props, pc_methods); */
  784.     PREF_GetConfigContext(&configContext);
  785.     PREF_GetGlobalConfigObject(&globalConfig);
  786.  
  787.     proxyConfig = JS_DefineObject(configContext, globalConfig, 
  788.                         "ProxyConfig",
  789.                         &pc_class, 
  790.                         NULL, 
  791.                         JSPROP_ENUMERATE);
  792.     if (proxyConfig) {
  793.         if (!JS_DefineProperties(configContext,
  794.                      proxyConfig,
  795.                      pc_props)) {
  796.         return;
  797.         }
  798.  
  799.         if (!JS_DefineFunctions(configContext,
  800.                     proxyConfig,
  801.                     pc_methods)) {
  802.         return;
  803.         }
  804.  
  805.     }
  806.  
  807.     JS_DefineObject(configContext, proxyConfig, 
  808.                     "bindings",
  809.                     &pc_class, 
  810.                     NULL, 
  811.                     0);
  812.     /*MOCHA_DefineNewObject(decoder->js_context, proxyConfig, "bindings",
  813.                   &pc_class, NULL, NULL, 0, no_props, 0); */
  814.  
  815.     }
  816.  
  817.     if (!pacf_src_buf) {
  818.     if ( pacf_do_failover == FALSE && !NET_UsingPadPac() ) {
  819.       /* Don't failover to using no proxies */
  820.          FE_Alert(obj->context, XP_GetString(XP_NO_CONFIG_RECEIVED_NO_FAILOVER));
  821.     }
  822.     else if (obj->flag != 2 && (XP_Stat("", &st, xpProxyConfig) == -1) && !NET_UsingPadPac())
  823.       {
  824.             FE_Alert(obj->context, XP_GetString(XP_NO_CONFIG_RECIEVED));
  825.       }
  826.     else
  827.     {
  828.         if(NET_UsingPadPac()) {
  829.             pacf_read_config();
  830.             obj->flag = 1;
  831.             goto retry;
  832.         } else if (obj->flag == 2 ||
  833.             confirm2(obj->context, XP_GetString(XP_EMPTY_CONFIG_USE_PREV), pacf_url)) {
  834.             pacf_read_config();
  835.             obj->flag = 1;
  836.             goto retry;
  837.         }
  838.     }
  839.     pacf_ok = FALSE;
  840.     goto out;
  841.     }
  842.  
  843.         ok = JS_EvaluateScript(configContext, proxyConfig, 
  844.                pacf_src_buf, pacf_src_len, pacf_url, 0,
  845.                &result);
  846.  
  847.     if (!ok) {
  848.         /* Something went wrong with the js evaluation. If we're using a
  849.          * proxy auto-discovery pac file, don't use it again. */
  850.         if(NET_UsingPadPac()) {
  851.             net_UsePadPac(FALSE);
  852.             goto out;
  853.         }
  854.         if (obj->flag) {
  855.                 FE_Alert(obj->context, XP_GetString(XP_EVEN_SAVED_IS_BAD));
  856.         } else if (XP_Stat("", &st, xpProxyConfig) == -1) {
  857.                 alert2(obj->context, XP_GetString(XP_BAD_CONFIG_IGNORED), pacf_url);
  858.         } else if (confirm2(obj->context, XP_GetString(XP_BAD_CONFIG_USE_PREV), pacf_url)) {
  859.               XP_FREE(pacf_src_buf);
  860.               pacf_src_buf = NULL;
  861.               pacf_src_len = 0;
  862.               pacf_read_config();
  863.               obj->flag = 1;            /* Uh (this is a horrid hack) */
  864.               goto retry;
  865.         }
  866.         pacf_ok = FALSE;
  867.         } else {
  868.         pacf_ok = TRUE;
  869.         if (!obj->flag) {
  870.             pacf_save_config();
  871.         }
  872.     }
  873.  
  874.     XP_FREE(obj);
  875.  
  876. out:
  877.     ;
  878. }
  879.  
  880. PRIVATE void pacf_abort(NET_StreamClass *stream, int status) {
  881.     PACF_Object *obj=stream->data_object;    
  882.     pacf_loading = FALSE;
  883.         FE_Alert(obj->context, XP_GetString(XP_GLOBAL_CONFIG_LOAD_ABORTED));
  884.     XP_FREE(obj);
  885. }
  886.  
  887. #endif /* MOCHA */
  888.  
  889. /* A stream constructor function for application/x-ns-proxy-autoconfig. 
  890.  * This is used by cvmime.c; it's registered as the stream converter for
  891.  * pac files. */
  892. MODULE_PRIVATE NET_StreamClass *
  893. NET_ProxyAutoConfig(int fmt, void *data_obj, URL_Struct *URL_s, 
  894.                     MWContext *w) {
  895. #ifdef MOCHA
  896.     PACF_Object         *obj;
  897.     NET_StreamClass     *stream;
  898.  
  899.     if (!pacf_loading) {
  900.     /*
  901.      * The Navigator didn't start this config retrieve
  902.      * intentionally.  Discarding the config.
  903.      */
  904.     if(!URL_s)
  905.         return NULL;
  906.     alert2(w, XP_GetString(XP_CONFIG_BLAST_WARNING), URL_s->address);
  907.     return NULL;
  908.     }
  909.     else {
  910.     NET_Progress(w, XP_GetString( XP_RECEIVING_PROXY_AUTOCFG ) ); 
  911.     }
  912.  
  913.     if (pacf_src_buf) {
  914.     XP_FREE(pacf_src_buf);
  915.     pacf_src_buf = NULL;
  916.     pacf_src_len = 0;
  917.     }
  918.  
  919.     if (!(stream = XP_NEW_ZAP(NET_StreamClass)))
  920.     return NULL;
  921.  
  922.     if (!(obj = XP_NEW_ZAP(PACF_Object))) {
  923.     XP_FREE(stream);
  924.     return NULL;
  925.     }
  926.  
  927.     obj->context = w;
  928.  
  929.     stream->data_object         = obj;
  930.     stream->name                = "ProxyAutoConfigLoader";
  931.     stream->complete            = (MKStreamCompleteFunc)  pacf_complete;
  932.     stream->abort               = (MKStreamAbortFunc)     pacf_abort;
  933.     stream->put_block           = (MKStreamWriteFunc)     pacf_write;
  934.     stream->is_write_ready      = (MKStreamWriteReadyFunc)pacf_write_ready;
  935.     stream->window_id           = w;
  936.  
  937.     return stream;
  938. #else   /* ! MOCHA */
  939.     return NULL;
  940. #endif  /* ! MOCHA */
  941. }
  942.  
  943. #ifdef MOCHA
  944.  
  945.  
  946. /* calls NET_GetURL() to get the url that had been queued up behind the 
  947.  * actual pac file url. */
  948. static void pacf_restart_queued(URL_Struct *URL_s, int status,
  949.                 MWContext *window_id) {
  950.     XP_StatStruct st;
  951.  
  952.     /* We want to fail silently if we're loading a pad pac and fail,
  953.      * so fall through to bottom and load the queued url. */
  954.     if (pacf_loading && !(NET_UsingPadPac() || foundPADPAC) ) {
  955.     
  956.     if ( pacf_do_failover == FALSE ) {
  957.       /* Don't failover to using no proxies */
  958.          FE_Alert(window_id, XP_GetString(XP_CONF_LOAD_FAILED_NO_FAILOVER));
  959.     }
  960.     else if (XP_Stat("", &st, xpProxyConfig) == -1)
  961.       {
  962.           if (status < 0)
  963.           FE_Alert(window_id, XP_GetString(XP_CONF_LOAD_FAILED_IGNORED));
  964.           else {
  965.                 alert2(window_id, XP_GetString(XP_BAD_TYPE_CONFIG_IGNORED), pacf_url);
  966.           }
  967.       }
  968.     else if (status == MK_INTERRUPTED)
  969.       {
  970.           /* silently fail and retry later */
  971.           NET_ProxyAcLoaded = FALSE;
  972.           NET_GlobalAcLoaded = FALSE;
  973.       }
  974.     else if (status < 0
  975.          ? FE_Confirm(window_id, XP_GetString(XP_CONF_LOAD_FAILED_USE_PREV))
  976.          : confirm2(window_id, XP_GetString(XP_BAD_TYPE_USE_PREV), pacf_url))
  977.       {
  978.           PACF_Object *obj = XP_NEW_ZAP(PACF_Object);
  979.           NET_StreamClass stream;
  980.           stream.data_object=obj;
  981.  
  982.           if (obj) {
  983.           obj->context = window_id;
  984.           obj->flag = 2;
  985.           pacf_complete(&stream);
  986.           }
  987.       }
  988.  
  989.     pacf_loading = FALSE;
  990.     } else {
  991.         /* Call this only if everything succeeded -- otherwise
  992.            the netlib has already freed the URL_s, and there isn't
  993.            a clean fix, so for now we'll just forget the URL load
  994.            if proxy config load went foul.
  995.          */
  996.         if(queued_state) {
  997.             NET_GetURL(queued_state->URL_s,
  998.                    queued_state->output_format,
  999.                    queued_state->window_id,
  1000.                    queued_state->exit_routine);
  1001.         }
  1002.     }
  1003.     XP_FREEIF(queued_state);
  1004.     queued_state = NULL;
  1005. }
  1006.  
  1007. #endif /* MOCHA */
  1008.  
  1009.  
  1010. /* Called by mkgeturl.c to originally retrieve, and re-retrieve
  1011.  * the proxy autoconfig file.
  1012.  *
  1013.  * autoconfig_url is the URL pointing to the autoconfig.
  1014.  *
  1015.  * The rest of the parameters are what was passed to NET_GetURL(),
  1016.  * and when the autoconfig load finishes NET_GetURL() will be called
  1017.  * with those exact same parameters.
  1018.  *
  1019.  * This is because the proxy config is loaded when NET_GetURL() is
  1020.  * called for the very first time, and the actual request must be put
  1021.  * on hold when the proxy config is being loaded.
  1022.  *
  1023.  * When called from the explicit proxy config RE-load function
  1024.  * NET_ReloadProxyConfig, the four last parameters are all zero,
  1025.  * and no request gets restarted. */
  1026. MODULE_PRIVATE int NET_LoadProxyConfig(char *autoconf_url,
  1027.                        URL_Struct *URL_s,
  1028.                        FO_Present_Types output_format,
  1029.                        MWContext *window_id,
  1030.                        Net_GetUrlExitFunc *exit_routine) {
  1031.     URL_Struct *my_url_s = NULL;
  1032.     char * global_url = NULL;
  1033.  
  1034.     if (!autoconf_url)
  1035.     return -1;
  1036.  
  1037.     if (!XP_STRCMP(autoconf_url,"BAD-NOAUTOADMNLIB")) {
  1038.         FE_Alert(window_id, XP_GetString( XP_AUTOADMIN_MISSING ));
  1039.         return -1;
  1040.     }
  1041.  
  1042.     StrAllocCopy(pacf_url, autoconf_url);
  1043.     my_url_s = NET_CreateURLStruct(autoconf_url, NET_SUPER_RELOAD);
  1044.  
  1045.     
  1046.     if (exit_routine) {
  1047.  
  1048.     queued_state = XP_NEW_ZAP(PACF_QueuedState);
  1049.     if(!queued_state)
  1050.         return -1;
  1051.     queued_state->URL_s = URL_s;
  1052.     queued_state->output_format = output_format;
  1053.     queued_state->window_id = window_id;
  1054.     queued_state->exit_routine = exit_routine;
  1055.  
  1056.     if(!my_url_s)
  1057.         return -1;
  1058.  
  1059.     my_url_s->pre_exit_fn = pacf_restart_queued;
  1060.     }
  1061.  
  1062.     /* Alert the proxy autoconfig module that config is coming */
  1063.     pacf_loading = TRUE;
  1064.     pacf_find_proxy_undefined = FALSE;
  1065.  
  1066.     return NET_GetURL(my_url_s, FO_PRESENT, window_id, NULL);
  1067. }
  1068.  
  1069. /* Returns a pointer to a NULL-terminted buffer which contains
  1070.  * the text of the proxy autoconfig file. */
  1071. PUBLIC char * NET_GetProxyConfigSource(void) {
  1072. #ifdef MOCHA
  1073.     return pacf_src_buf;
  1074. #else
  1075.     return 0;
  1076. #endif
  1077. }
  1078.  
  1079.  
  1080.  /* Given a URL, returns the proxy that should be used.
  1081.  * The proxy is determined by the proxy autoconfig file,
  1082.  * which is a JavaScript routine. */
  1083. MODULE_PRIVATE char *pacf_find_proxies_for_url(MWContext *context, 
  1084.                                                URL_Struct *URL_s ) {
  1085. #ifdef MOCHA
  1086.     jsval rv;
  1087.     char *buf = NULL;
  1088.     char *host = NULL;
  1089.     char *p, *q, *r;
  1090.     int i, len = 0;
  1091.     char *safe_url = NULL;
  1092.     char *orig_url = NULL;
  1093.     char *method = NULL;
  1094.     char *bad_url = NULL;
  1095.     char *result = NULL;
  1096.     JSBool ok;
  1097.  
  1098.     if(!URL_s)
  1099.         return NULL;
  1100.  
  1101.     orig_url=URL_s->address;
  1102.     method=mkMethodString(URL_s->method);
  1103.  
  1104.     /* If proxy failover is not allowed, and we weren't
  1105.      * able to autoload the proxy, return a string that
  1106.      * pacf_get_proxy_addr will always fail with. */
  1107.     if ( !pacf_do_failover && !pacf_loading && !pacf_ok ) {
  1108.       return "";
  1109.     }
  1110.  
  1111.     if (!orig_url || !pacf_ok || pacf_loading || pacf_find_proxy_undefined)
  1112.     return NULL;
  1113.  
  1114.     if (!(bad_url = XP_STRDUP(orig_url)))
  1115.     goto out;
  1116.  
  1117.     len = NET_UnEscapeCnt(bad_url);
  1118.  
  1119.     if (!(safe_url = XP_ALLOC(2 * len + 1)))    /* worst case */
  1120.     goto out;
  1121.  
  1122.     p = bad_url;
  1123.     q = safe_url;
  1124.     for(i=0; i<len; i++, p++) {
  1125.     switch (*p) {
  1126.       case '\n':
  1127.         *q++ = '\\';
  1128.         *q++ = 'n';
  1129.         break;
  1130.       case '\r':
  1131.         *q++ = '\\';
  1132.         *q++ = 'r';
  1133.         break;
  1134.       case '\0':
  1135.         *q++ = '\\';
  1136.         *q++ = '0';
  1137.         break;
  1138.       case '"':
  1139.         *q++ = '\\';
  1140.         *q++ = '"';
  1141.         break;
  1142.       case '\\':
  1143.         *q++ = '\\';
  1144.         *q++ = '\\';
  1145.         break;
  1146.       default:
  1147.         *q++ = *p;
  1148.     }
  1149.     }
  1150.     *q = '\0';
  1151.  
  1152.     len  = (int)(q - safe_url);
  1153.  
  1154.     if (!(host = XP_ALLOC(len + 1)))
  1155.     goto out;
  1156.  
  1157.     if (!(buf  = XP_ALLOC(len*2 + 50)))
  1158.     goto out;
  1159.  
  1160.     host[0] = '\0';
  1161.  
  1162.     p = XP_STRSTR(safe_url, "://");
  1163.     if (p) {
  1164.     p += 3;
  1165.     q = XP_STRCHR(p, '/');
  1166.     if (q)
  1167.         *q = '\0';
  1168.     r = XP_STRCHR(p, '@');
  1169.     if (r)
  1170.         p = r + 1;
  1171.     XP_STRCPY(host, p);
  1172.     if (q)
  1173.         *q = '/';
  1174.     p = XP_STRCHR(host, ':');
  1175.     if (p)
  1176.         *p = '\0';
  1177.     }
  1178.         XP_SPRINTF(buf, "FindProxyForURL(\"%s\",\"%s\",\"%s\")", safe_url, host,
  1179.            method ? method : "" );
  1180.  
  1181.     if (!JS_AddRoot(configContext, &rv))
  1182.     goto out;
  1183.  
  1184.         ok = JS_EvaluateScript(configContext, proxyConfig,
  1185.                buf, strlen(buf), 0, 0, &rv);
  1186.  
  1187.     if (ok) {
  1188.     if (JSVAL_IS_STRING(rv)) {
  1189.         const char *name =
  1190.         JS_GetStringBytes(JSVAL_TO_STRING(rv));
  1191.         if (*name)
  1192.         result = XP_STRDUP(name);
  1193.     }
  1194.     }
  1195.  
  1196.     JS_RemoveRoot(configContext, &rv);
  1197. out:
  1198.     FREEIF(method);
  1199.     FREEIF(buf);
  1200.     FREEIF(host);
  1201.     FREEIF(safe_url);
  1202.     FREEIF(bad_url);
  1203.     return result;
  1204.  
  1205. #else   /* ! MOCHA */
  1206.  
  1207.     return NULL;
  1208. #endif  /* ! MOCHA */
  1209. }
  1210.  
  1211. #ifdef MOCHA
  1212.  
  1213. /* Utility functions to be called from Javascript (aka Mocha).
  1214.  * These are the actual implementations of the javascript fucntions that
  1215.  * are in the javascript pac file.
  1216.  *
  1217.  * Get the number of DNS domain levels (number of dots):
  1218.  *
  1219.  *      dnsDomainLevels(host)
  1220.  *
  1221.  *
  1222.  * Host/URL based conditions:
  1223.  *
  1224.  *      isPlainHostName(host)
  1225.  *      dnsDomainIs(host, name)
  1226.  *      localHostOrDomainIs(host, name)
  1227.  *      isResolvable(host)
  1228.  *      regExpMatch(host or URL, regexp)
  1229.  *
  1230.  *
  1231.  * Date/time based conditions (limits inclusive):
  1232.  *
  1233.  *      weekdayRange(wkday)
  1234.  *      weekdayRange(wkday, wkday)
  1235.  *
  1236.  *      dateRange(day)
  1237.  *      dateRange(day, day)
  1238.  *      dateRange(mon)
  1239.  *      dateRange(mon, mon)
  1240.  *      dateRange(year)
  1241.  *      dateRange(year, year)
  1242.  *      dateRange(day, mon, day, mon)
  1243.  *      dateRange(mon, year, mon, year)
  1244.  *      dateRange(day, mon, year, day, mon, year)
  1245.  *
  1246.  *      timeRange(hour)
  1247.  *      timeRange(hour, hour)
  1248.  *      timeRange(hour, min, hour, min)
  1249.  *      timeRange(hour, min, sec, hour, min, sec)
  1250.  *
  1251.  *
  1252.  *
  1253.  */
  1254.  
  1255. /* Returns true if the hostname doesn't contain a dot
  1256.  * (is a plain hostname, not an FQDN).
  1257.  *
  1258.  * Just a string operation, doesn't consult DNS. */
  1259. MODULE_PRIVATE JSBool PR_CALLBACK
  1260. proxy_isPlainHostName(JSContext *mc, JSObject *obj, unsigned int argc, 
  1261.                       jsval *argv, jsval *rval) {
  1262.     if (argc >= 1 && JSVAL_IS_STRING(argv[0])) {
  1263.     const char *h = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
  1264.  
  1265.     if (h && !XP_STRCHR(h, '.')) {
  1266.         *rval = JSVAL_TRUE;
  1267.         return JS_TRUE;
  1268.     }
  1269.     }
  1270.  
  1271.     *rval = JSVAL_FALSE;
  1272.     return JS_TRUE;
  1273. }
  1274.  
  1275. /* Returns the number of domain levels in the hostname
  1276.  * (the number of dots, actually).
  1277.  *
  1278.  * Just a string operation, doesn't consult DNS. */
  1279. MODULE_PRIVATE JSBool PR_CALLBACK
  1280. proxy_dnsDomainLevels(JSContext *mc, JSObject *obj, unsigned int argc, 
  1281.                       jsval *argv, jsval *rval) {
  1282.     int i = 0;
  1283.  
  1284.     if (argc >= 1 && JSVAL_IS_STRING(argv[0])) {
  1285.     const char *h = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
  1286.  
  1287.     if (h) {
  1288.         while (*h) {
  1289.         if (*h == '.')
  1290.             i++;
  1291.         h++;
  1292.         }
  1293.     }
  1294.     }
  1295.  
  1296.     *rval = INT_TO_JSVAL(i);
  1297.     return JS_TRUE;
  1298. }
  1299.  
  1300. /* Checks if the hostname contains the given domain. */
  1301. MODULE_PRIVATE JSBool PR_CALLBACK
  1302. proxy_dnsDomainIs(JSContext *mc, JSObject *obj, unsigned int argc, 
  1303.                   jsval *argv, jsval *rval) {
  1304.     if (argc >= 2 && JSVAL_IS_STRING(argv[0]) && JSVAL_IS_STRING(argv[1])) {
  1305.     const char *h = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
  1306.     const char *p = JS_GetStringBytes(JSVAL_TO_STRING(argv[1]));
  1307.     int len1, len2;
  1308.  
  1309.     if (h && p && (len1 = XP_STRLEN(h)) >= (len2 = XP_STRLEN(p)) &&
  1310.         (!strcasecomp(h + len1 - len2, p))) {
  1311.         *rval = JSVAL_TRUE;
  1312.         return JS_TRUE;
  1313.     }
  1314.     }
  1315.  
  1316.     *rval = JSVAL_FALSE;
  1317.     return JS_TRUE;
  1318. }
  1319.  
  1320. /* Returns true if the hostname matches exactly the given
  1321.  * pattern hostname, or if the hostname is just a local hostname
  1322.  * and it matches the hostname in the pattern FQDN hostname. */
  1323. MODULE_PRIVATE JSBool PR_CALLBACK
  1324. proxy_localHostOrDomainIs(JSContext *mc, JSObject *obj, unsigned int argc, 
  1325.                           jsval *argv, jsval *rval) {
  1326.     if (argc >= 2 && JSVAL_IS_STRING(argv[0]) && JSVAL_IS_STRING(argv[1])) {
  1327.     const char *h = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
  1328.     const char *p = JS_GetStringBytes(JSVAL_TO_STRING(argv[1]));
  1329.     char *hp, *pp;
  1330.  
  1331.     if (h && p) {
  1332.         hp = XP_STRCHR(h, '.');
  1333.         pp = XP_STRCHR(p, '.');
  1334.  
  1335.         if (hp || !pp) {
  1336.         if (!strcasecomp(h,p)) {
  1337.             *rval = JSVAL_TRUE;
  1338.             return JS_TRUE;
  1339.         }
  1340.         }
  1341.         else if (!strncasecomp(h, p, pp - p)) {
  1342.         *rval = JSVAL_TRUE;
  1343.         return JS_TRUE;
  1344.         }
  1345.     }
  1346.     }
  1347.  
  1348.     *rval = JSVAL_FALSE;
  1349.     return JS_TRUE;
  1350. }
  1351.  
  1352. /* Attempts to resolve the DNS name, and returns TRUE if resolvable. */
  1353. MODULE_PRIVATE JSBool PR_CALLBACK
  1354. proxy_isResolvable(JSContext *mc, JSObject *obj, unsigned int argc, 
  1355.                    jsval *argv, jsval *rval) {
  1356.     if (argc >= 1 && JSVAL_IS_STRING(argv[0])) {
  1357.     const char *h = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
  1358.     PRHostEnt *hp = NULL;
  1359. #ifdef NSPR20
  1360.     PRStatus rv;
  1361.     PRHostEnt hpbuf;
  1362.     char dbbuf[PR_NETDB_BUF_SIZE];
  1363. #elif defined(XP_UNIX) || defined(XP_WIN32)
  1364.     PRHostEnt hpbuf;
  1365.     char dbbuf[PR_NETDB_BUF_SIZE];
  1366. #endif
  1367.  
  1368.     if (h) {
  1369.         char *safe = XP_STRDUP(h);
  1370.         if (XP_STRLEN(safe) > 64)
  1371.         safe[64] = '\0';
  1372. #ifdef NSPR20
  1373.         rv = PR_GetHostByName(safe, dbbuf, sizeof(dbbuf),  &hpbuf);
  1374.         hp = (rv == PR_SUCCESS ? &hpbuf : NULL);
  1375. #elif defined(XP_UNIX) || defined(XP_WIN32)
  1376.         hp = PR_gethostbyname(safe, &hpbuf, dbbuf, sizeof(dbbuf), 0);
  1377. #else
  1378.         hp = gethostbyname(safe);
  1379. #endif
  1380.         XP_FREE(safe);
  1381.     }
  1382.  
  1383.     if (hp) {
  1384.         TRACEMSG(("~~~~~~~~~~~ isResolvable(%s) returns TRUE\n", h));
  1385.         TRACEMSG(("~~~~~~~~~~~ hp = %p, hp->h_name = %s\n", hp, hp->h_name ? hp->h_name : "(null)"));
  1386.         *rval = JSVAL_TRUE;
  1387.         return JS_TRUE;
  1388.     }
  1389.     }
  1390.  
  1391.     TRACEMSG(("~~~~~~~~~~~ isResolvable(%s) returns FALSE\n", argv[0]));
  1392.     *rval = JSVAL_FALSE;
  1393.     return JS_TRUE;
  1394. }
  1395.  
  1396. /* Resolves a DNS name, and returns the IP address string.
  1397.  *
  1398.  * Maintains a private cache for the last resolved address (so this
  1399.  * function can be called multiple times with the same host argument
  1400.  * without doing actual DNS queries every time). */
  1401. PRIVATE char *proxy_dns_resolve(const char *host) {
  1402.     static char *cache_host = NULL;
  1403.     static char *cache_ip = NULL;
  1404. #ifdef NSPR20
  1405.     PRStatus rv;
  1406.     PRHostEnt *hp = NULL;
  1407.     PRHostEnt hpbuf;
  1408.     char dbbuf[PR_NETDB_BUF_SIZE];
  1409. #else
  1410.     struct hostent *hp = NULL;
  1411. #if defined(XP_UNIX) || defined(XP_WIN32)
  1412.     struct hostent hpbuf;
  1413.     char dbbuf[PR_NETDB_BUF_SIZE];
  1414. #endif
  1415. #endif /* xNSPR20 */
  1416.  
  1417.     if (host) {
  1418.     const char *p;
  1419.     char *safe = NULL;
  1420.     XP_Bool is_numeric_ip = TRUE;
  1421.  
  1422.     for(p=host; *p; p++) {
  1423.         if (!XP_IS_DIGIT(*p) && *p != '.') {
  1424.         is_numeric_ip = FALSE;
  1425.         break;
  1426.         }
  1427.     }
  1428.     if (is_numeric_ip) {
  1429.         return XP_STRDUP(host);
  1430.     }
  1431.  
  1432.     if (cache_host && cache_ip && !XP_STRCMP(cache_host, host)) {
  1433.         return XP_STRDUP(cache_ip);
  1434.     }
  1435.     safe = XP_STRDUP(host);
  1436.     if (safe) {
  1437.         if (XP_STRLEN(safe) > 64)
  1438.         safe[64] = '\0';
  1439.  
  1440. #ifdef NSPR20
  1441.         rv = PR_GetHostByName(safe, dbbuf, sizeof(dbbuf),  &hpbuf);
  1442.         hp = (rv == PR_SUCCESS ? &hpbuf : NULL);
  1443. #elif defined(XP_UNIX) || defined(XP_WIN32)
  1444.         hp = PR_gethostbyname(safe, &hpbuf, dbbuf, sizeof(dbbuf), 0);
  1445. #else
  1446.         hp = gethostbyname(safe);
  1447. #endif
  1448.         XP_FREE(safe);
  1449.     }
  1450.     if (hp) {
  1451.         char *ip = NULL;
  1452.         struct in_addr in;
  1453.  
  1454.         XP_MEMCPY(&in.s_addr, hp->h_addr, hp->h_length);
  1455.  
  1456.         ip = inet_ntoa(in);
  1457.         if (ip) {
  1458.         StrAllocCopy(cache_host, host);
  1459.         StrAllocCopy(cache_ip, ip);
  1460.  
  1461.         return XP_STRDUP(ip);
  1462.         }
  1463.     }
  1464.     }
  1465.  
  1466.     return NULL;
  1467. }
  1468.  
  1469. MODULE_PRIVATE JSBool PR_CALLBACK
  1470. proxy_dnsResolve(JSContext *mc, JSObject *obj, unsigned int argc, 
  1471.                  jsval *argv, jsval *rval) {
  1472.     if (argc >= 1 && JSVAL_IS_STRING(argv[0])) {
  1473.     const char *host = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
  1474.     char *ip = proxy_dns_resolve(host);
  1475.  
  1476.     if (ip) {
  1477.         JSString * str = JS_NewString(mc, ip, strlen(ip));
  1478.         if (!str) {
  1479.         XP_FREE(ip);
  1480.         return JS_FALSE;
  1481.         }
  1482.         *rval = STRING_TO_JSVAL(str);
  1483.         return JS_TRUE;
  1484.     }
  1485.     }
  1486.  
  1487.     *rval = JSVAL_NULL;
  1488.     return JS_TRUE;
  1489. }
  1490.  
  1491. /* Returns the IP address of the host machine as a string. */
  1492. MODULE_PRIVATE JSBool PR_CALLBACK
  1493. proxy_myIpAddress(JSContext *mc, JSObject *obj, unsigned int argc, 
  1494.                   jsval *argv, jsval *rval) {
  1495.     static XP_Bool initialized = FALSE;
  1496.     static char *my_address = NULL;
  1497.  
  1498.     if (!initialized) {
  1499.     char name[100];
  1500.  
  1501.     initialized = TRUE;
  1502. #ifndef NSPR20
  1503.     if (gethostname(name, sizeof(name)) == 0) {
  1504.         my_address = proxy_dns_resolve(name);
  1505.     }
  1506. #else
  1507.     if (PR_GetSystemInfo(PR_SI_HOSTNAME, name, sizeof(name)) == PR_SUCCESS) {
  1508.         my_address = proxy_dns_resolve(name);
  1509.     }
  1510. #endif
  1511.     }
  1512.  
  1513.     TRACEMSG(("~~~~~~~~~~~~~~~~~~ myIpAddress() returns %s\n", my_address ? my_address : "(null)"));
  1514.  
  1515.     if (my_address) {
  1516.         JSString *str;
  1517.     str = JS_NewStringCopyZ(mc, my_address);
  1518.     if (!str)
  1519.         return JS_FALSE;
  1520.     *rval = STRING_TO_JSVAL(str);
  1521.     return JS_TRUE;
  1522.     }
  1523.  
  1524.     *rval = JSVAL_NULL;
  1525.     return JS_TRUE;
  1526. }
  1527.  
  1528. /* Determines if the host IP address belongs to the given network.
  1529.  * Uses SOCKS style address pattern and mask:
  1530.  *
  1531.  *      isInNet(hostname, "111.222.33.0", "255.255.255.0"); */
  1532. PRIVATE unsigned long convert_addr(const char *ip) {
  1533.     char *p, *q, *buf = NULL;
  1534.     int i;
  1535.     unsigned char b[4];
  1536.     unsigned long addr = 0L;
  1537.  
  1538.     p = buf = XP_STRDUP(ip);
  1539.     if (ip && p) {
  1540.     for(i=0; p && i<4; i++) {
  1541.         q = XP_STRCHR(p, '.');
  1542.         if (q) {
  1543.         *q = '\0';
  1544.         }
  1545.         b[i] = XP_ATOI(p) & 0xff;
  1546.         if (q) {
  1547.         p = q+1;
  1548.         }
  1549.     }
  1550.     addr = (((unsigned long)b[0] << 24) |
  1551.         ((unsigned long)b[1] << 16) |
  1552.         ((unsigned long)b[2] <<  8) |
  1553.         ((unsigned long)b[3]));
  1554.  
  1555.     XP_FREE(buf);
  1556.     }
  1557.  
  1558.     return htonl(addr);
  1559. }
  1560.  
  1561. MODULE_PRIVATE JSBool PR_CALLBACK
  1562. proxy_isInNet(JSContext *mc, JSObject *obj, unsigned int argc, 
  1563.               jsval *argv, jsval *rval) {
  1564.     if (argc >= 3 &&
  1565.     JSVAL_IS_STRING(argv[0]) &&
  1566.     JSVAL_IS_STRING(argv[1]) &&
  1567.     JSVAL_IS_STRING(argv[2]))
  1568.       {
  1569.       const char *ipstr = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
  1570.       char *ip = proxy_dns_resolve(ipstr);
  1571.       const char *patstr = JS_GetStringBytes(JSVAL_TO_STRING(argv[1]));
  1572.       const char *maskstr = JS_GetStringBytes(JSVAL_TO_STRING(argv[2]));
  1573.  
  1574.       if (ip) {
  1575.           unsigned long host = convert_addr(ip);
  1576.           unsigned long pat  = convert_addr(patstr);
  1577.           unsigned long mask = convert_addr(maskstr);
  1578.  
  1579.           XP_FREE(ip);
  1580.  
  1581.           if ((mask & host) == (mask & pat)) {
  1582.           TRACEMSG(("~~~~~~~~~~~~ isInNet(%s(%s), %s, %s) returns TRUE\n",
  1583.                 ipstr, ip, patstr, maskstr));
  1584.             *rval = JSVAL_TRUE;
  1585.             return JS_TRUE;
  1586.           }
  1587.       }
  1588.       }
  1589.  
  1590.     TRACEMSG(("~~~~~~~~~~~~ isInNet() returns FALSE\n"));
  1591.  
  1592.     *rval = JSVAL_FALSE;
  1593.     return JS_TRUE;
  1594. }
  1595.  
  1596. /* Does a regular expression match between the host/URL and the pattern.
  1597.  *
  1598.  * Returns true on match. */
  1599. MODULE_PRIVATE JSBool PR_CALLBACK
  1600. proxy_regExpMatch(JSContext *mc, JSObject *obj, unsigned int argc, 
  1601.                   jsval *argv, jsval *rval) {
  1602.     if (argc >= 2 && JSVAL_IS_STRING(argv[0]) && JSVAL_IS_STRING(argv[1])) {
  1603.     const char *url = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
  1604.     const char *pat = JS_GetStringBytes(JSVAL_TO_STRING(argv[1]));
  1605.  
  1606.     if (url && pat && XP_RegExpValid((char *) pat) &&       /* XXX */
  1607.         !XP_RegExpMatch((char *) url, (char *) pat, TRUE)) {/* XXX */
  1608.         *rval = JSVAL_TRUE;
  1609.         return JS_TRUE;
  1610.     }
  1611.     }
  1612.  
  1613.     *rval = JSVAL_FALSE;
  1614.     return JS_TRUE;
  1615. }
  1616.  
  1617. PRIVATE
  1618. struct tm * get_struct_tm(JSContext *mc,
  1619.               unsigned int *argc, jsval *argv) {
  1620.     time_t now = time(NULL);
  1621.  
  1622.     if (*argc > 0 &&  JSVAL_IS_STRING(argv[*argc-1])) {
  1623.     const char *laststr = JS_GetStringBytes(JSVAL_TO_STRING(argv[*argc-1]));
  1624.     if (!strcasecomp(laststr, "GMT")) {
  1625.         (*argc)--;
  1626.         return gmtime(&now);
  1627.     }
  1628.     }
  1629.     return localtime(&now);
  1630. }
  1631.  
  1632. char *weekdays = "SUNMONTUEWEDTHUFRISAT";
  1633. char *monnames = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
  1634.  
  1635. PRIVATE int get_no(const char *nam, char *arr) {
  1636.     char *p = strcasestr(arr, nam);
  1637.     return p ? (((int)(p - arr)) / 3) : -1;
  1638. }
  1639.  
  1640. PRIVATE int get_em(JSContext *mc, int argc, jsval *argv,
  1641.            int *d, int *m, int *y) {
  1642.     int i=0;
  1643.  
  1644.     *m = *d = *y = -1;
  1645.  
  1646.     for (i=0; i<argc; i++) {
  1647.     if (JSVAL_IS_STRING(argv[i])) {
  1648.         *m = get_no(JS_GetStringBytes(JSVAL_TO_STRING(argv[i])), monnames);
  1649.     } 
  1650.     else if (JSVAL_IS_NUMBER(argv[i])) {
  1651.         if (JSVAL_TO_INT(argv[i]) > 1900)
  1652.         *y = JSVAL_TO_INT(argv[i]) - 1900;
  1653.         else
  1654.         *d = JSVAL_TO_INT(argv[i]);
  1655.     } 
  1656.     else {
  1657.         assert(0);
  1658.     }
  1659.     }
  1660.     return ((*d > -1 ? 1 : 0) +
  1661.         (*m > -1 ? 1 : 0) +
  1662.         (*y > -1 ? 1 : 0));
  1663. }
  1664.  
  1665. PRIVATE int are_different(JSContext *mc, jsval *argv) {
  1666.     int d1, d2, m1, m2, y1, y2;
  1667.  
  1668.     get_em(mc, 1,  argv,    &d1, &m1, &y1);
  1669.     get_em(mc, 1, &argv[1], &d2, &m2, &y2);
  1670.  
  1671.     return ((d1 == -1 || d2 == -1) &&
  1672.         (m1 == -1 || m2 == -1) &&
  1673.         (y1 == -1 || y2 == -1));
  1674. }
  1675.  
  1676. PRIVATE long get_rel(int sel_d, int sel_m, int sel_y, int d, int m, int y) {
  1677.     return ((sel_d > -1 ? d : 0) +
  1678.         (sel_m > -1 ? m : 0) * 31 +
  1679.         (sel_y > -1 ? y : 0) * 372);
  1680. }
  1681.  
  1682. PRIVATE int cmp_properly(int sel_y, long rel_lo, long rel, long rel_hi) {
  1683.     if (sel_y || rel_lo < rel_hi)
  1684.     return rel_lo <= rel && rel <= rel_hi;
  1685.     else
  1686.     return rel_lo <= rel || rel <= rel_hi;
  1687. }
  1688.  
  1689. MODULE_PRIVATE JSBool PR_CALLBACK
  1690. proxy_dateRange(JSContext *mc, JSObject *obj, unsigned int argc, 
  1691.                 jsval *argv, jsval *rval) {
  1692.     int d1, d2, m1, m2, y1, y2;
  1693.     struct tm *tms = get_struct_tm(mc, &argc, argv);
  1694.  
  1695.     d1 = d2 = m1 = m2 = y1 = y2 = -1;
  1696.  
  1697.     if (argc == 1 || argc == 3 || (argc==2 && are_different(mc, argv)))
  1698.       {
  1699.       *rval = ((get_em(mc, argc, argv, &d1, &m1, &y1) &&
  1700.            (d1 == -1 || d1 == tms->tm_mday)  &&
  1701.            (m1 == -1 || m1 == tms->tm_mon)   &&
  1702.            (y1 == -1 || y1 == tms->tm_year))
  1703.           ? JSVAL_TRUE : JSVAL_FALSE);
  1704.       }
  1705.     else
  1706.       {
  1707.       *rval = (((get_em(mc, argc/2,  argv,         &d1, &m1, &y1) ==
  1708.              get_em(mc, argc/2, &argv[argc/2], &d2, &m2, &y2))   &&
  1709.            cmp_properly(y1,
  1710.                 get_rel(d1, m1, y1, d1, m1, y1),
  1711.                 get_rel(d1, m1, y1, tms->tm_mday, tms->tm_mon, tms->tm_year),
  1712.                 get_rel(d1, m1, y1, d2, m2, y2)))
  1713.           ? JSVAL_TRUE : JSVAL_FALSE);
  1714.       }
  1715.     return JS_TRUE;
  1716. }
  1717.  
  1718. MODULE_PRIVATE JSBool PR_CALLBACK
  1719. proxy_weekdayRange(JSContext *mc, JSObject *obj, unsigned int argc, 
  1720.                    jsval *argv, jsval *rval) {
  1721.     struct tm *tms = get_struct_tm(mc, &argc, argv);
  1722.     int i=0, j=0;
  1723.  
  1724.     if (argc >= 1)
  1725.     i = get_no(JS_GetStringBytes(JSVAL_TO_STRING(argv[0])), weekdays);
  1726.     if (argc >= 2)
  1727.     j = get_no(JS_GetStringBytes(JSVAL_TO_STRING(argv[1])), weekdays);
  1728.  
  1729.     *rval = (((argc == 1 && i == tms->tm_wday) ||
  1730.           (argc == 2 && ((i <= j && (i <= tms->tm_wday && j >= tms->tm_wday)) ||
  1731.                 (i >  j && (i <= tms->tm_wday || j >= tms->tm_wday)))))
  1732.         ? JSVAL_TRUE : JSVAL_FALSE);
  1733.     return JS_TRUE;
  1734. }
  1735.  
  1736. /* timeRange(<hr>)
  1737.  * timeRange(<hr>, <hr>)
  1738.  * timeRange(<hr>, <min>, <hr>, <min>)
  1739.  * timeRange(<hr>, <min>, <sec>, <hr>, <min>, <sec>) */
  1740. MODULE_PRIVATE JSBool PR_CALLBACK
  1741. proxy_timeRange(JSContext *mc, JSObject *obj, unsigned int argc, 
  1742.                 jsval *argv, jsval *rval) {
  1743.     int32 secondsA=0, secondsB=0, secondsC=0;
  1744.     struct tm *tms = get_struct_tm(mc, &argc, argv);
  1745.  
  1746.     if(argc == 1) {
  1747.         secondsA = JSVAL_TO_INT(argv[0])*60*60;
  1748.         secondsB = tms->tm_hour*60*60;
  1749.         *rval = (secondsA == secondsB) ? JSVAL_TRUE : JSVAL_FALSE;
  1750.         return JS_TRUE;
  1751.     }
  1752.     if(argc == 2) {
  1753.         secondsA = JSVAL_TO_INT(argv[0])*60*60;
  1754.         secondsB = tms->tm_hour*60*60;
  1755.         secondsC = JSVAL_TO_INT(argv[1])*60*60;
  1756.     }
  1757.     if(argc == 4) {
  1758.         secondsA = JSVAL_TO_INT(argv[0])*60*60 + JSVAL_TO_INT(argv[1])*60;
  1759.         secondsB = tms->tm_hour*60*60 + tms->tm_min*60;
  1760.         secondsC = JSVAL_TO_INT(argv[2])*60*60 + JSVAL_TO_INT(argv[3])*60;
  1761.     }
  1762.     if(argc == 6) {
  1763.         secondsA = JSVAL_TO_INT(argv[0])*60*60 + JSVAL_TO_INT(argv[1])*60 + JSVAL_TO_INT(argv[2]);
  1764.         secondsB = tms->tm_hour*60*60 + tms->tm_min*60 + tms->tm_sec;
  1765.         secondsC = JSVAL_TO_INT(argv[3])*60*60 + JSVAL_TO_INT(argv[4])*60 + JSVAL_TO_INT(argv[5]);
  1766.     }
  1767.     *rval = (secondsA <= secondsB && secondsB < secondsC) ? JSVAL_TRUE : JSVAL_FALSE;
  1768.     return JS_TRUE;
  1769. }
  1770.  
  1771. #endif /* MOCHA */
  1772.