[w3m-dev-en 00191] sorry, the last patch was not made properly

From: Ambrose Li [EDP] (acli@mingpaoxpress.com)
Date: Thu Jul 06 2000 - 17:51:31 CDT


Sorry, the patch I just sent was not made properly. The correct patch is
below.

diff -u w3m-0.1.10.dist/configure w3m-0.1.10-ja/configure
--- w3m-0.1.10.dist/configure Mon Jun 5 05:41:35 2000
+++ w3m-0.1.10-ja/configure Thu Jul 6 15:37:12 2000
@@ -576,7 +576,7 @@
 fi
 
 echo "Do you want to use SSL?"
-echo '(You need openSSL library; Please see http://www.openssl.org/)'
+echo '(You need OpenSSL library; Please see http://www.openssl.org/)'
 yesno use_ssl "$use_ssl" n
 echo "use_ssl=$use_ssl" >> config.param
 if [ "$use_ssl" = y ]; then
@@ -592,6 +592,7 @@
 
 if [ "$use_ssl" = y ]; then
   echo "Do you want SSL verification support"
+ echo '(Your SSL library must be version 0.8 or later)'
   yesno use_ssl_verify "$use_ssl_verify" n
   echo "use_ssl_verify=$use_ssl_verify" >> config.param
   if [ "$use_ssl_verify" = y ]; then
diff -u w3m-0.1.10.dist/cookie.c w3m-0.1.10-ja/cookie.c
--- w3m-0.1.10.dist/cookie.c Tue Jun 6 01:39:13 2000
+++ w3m-0.1.10-ja/cookie.c Thu Jul 6 16:22:25 2000
@@ -20,6 +20,7 @@
 {
     int m0, m1, offset;
 
+ /* RFC 2109 s. 2, "domain-match", case 1 (both are IP and identical) */
     regexCompile("[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*", 0);
     m0 = regexMatch(host, 1);
     m1 = regexMatch(domain, 1);
@@ -27,6 +28,7 @@
         if (strcasecmp(host, domain) == 0)
             return host;
     }
+ /* RFC 2109 s. 2, cases 2, 3 */
     else if (!m0 && !m1) {
         offset = (domain[0] != '.') ? 0 : strlen(host) - strlen(domain);
         if (offset >= 0 && strcasecmp(&host[offset], domain) == 0)
@@ -35,6 +37,70 @@
     return NULL;
 }
 
+static char *
+tail_match(char *host, char *domain)
+{
+ int m0, m1;
+
+ /* http://www.netscape.com/newsref/std/cookie_spec.html defined
+ "tail-matching" quite sloppily. In particular case 1 of RFC 2109
+ s. 2 was not considered. We use RFC 2109 semantics in the case
+ where IP numbers are involved. */
+
+ regexCompile("[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*\\.[0-9][0-9]*",0);
+ m0 = regexMatch(host,1);
+ m1 = regexMatch(domain,1);
+ if (m0 && m1 && strcmp(host, domain) == 0) {
+ return host;
+
+ /* Version 0 "tail-matching" for non-IP-number hosts names */
+ } else if (!m0 && !m1 && !nodots(host, NULL)) {
+ if (strcasecmp(host, domain) == 0) {
+ return host;
+ } else {
+ int L_host = strlen(host);
+ int L_domain = strlen(domain);
+ if (L_host >= L_domain + 1
+ && domain[0] == '.'
+ && strcasecmp(&host[L_host - L_domain], domain) == 0)
+ /* domain actually starts with a . (i.e., same as RFC 2109) */
+ return &host[L_host - L_domain];
+ else if (L_host >= L_domain + 2
+ && host[L_host - L_domain - 1] == '.'
+ && strcasecmp(&host[L_host - L_domain], domain) == 0)
+ /* domain has no leading dot */
+ return &host[L_host - L_domain - 1];
+ }
+ }
+ return NULL;
+}
+
+static char *
+domain_or_tail_match(char *host, char *domain, int version)
+{
+ return version? domain_match(host, domain): tail_match(host, domain);
+}
+
+static char *
+fqdn( char *host, int scheme )
+{
+ /* This is a wrapper for the FQDN() function.
+
+ Note that if we are using a valid proxy, we will want to avoid calling
+ FQDN() to avoid resolving domain names twice, with the results of the
+ client-side resolution effectively discarded. We presumably only get a
+ cookie if we use HTTP or HTTPS, vs. FTP etc., so we ignore other scheme.
+ Note that we have no "HTTPS proxy" setting. */
+
+ char *domainname = NULL;
+ if (scheme == SCM_HTTP && HTTP_proxy != NULL && !Do_not_use_proxy && !check_no_proxy(host)) {
+ domainname = host;
+ } else {
+ domainname = FQDN(host);
+ }
+ return domainname;
+}
+
 static struct portlist *
 make_portlist(Str port)
 {
@@ -122,12 +188,12 @@
 static int
 match_cookie(ParsedURL * pu, struct cookie *cookie)
 {
- char *domainname = FQDN(pu->host);
+ char *domainname = fqdn(pu->host, pu->scheme);
 
     if (!domainname)
         return 0;
 
- if (!domain_match(domainname, cookie->domain->ptr))
+ if (!domain_or_tail_match(domainname, cookie->domain->ptr, cookie->version))
         return 0;
     if (strncmp(cookie->path->ptr, pu->file, cookie->path->length) != 0)
         return 0;
@@ -184,6 +250,7 @@
         return NULL;
 
     tmp = Strnew();
+ /* XXX The version check is not necessary according to RFC 2109 s. 10.1.1 */
     if (version > 0)
         Strcat(tmp, Sprintf("$Version=\"%d\"; ", version));
 
@@ -191,6 +258,7 @@
     for (p1 = fco->next; p1; p1 = p1->next) {
         Strcat_charp(tmp, "; ");
         Strcat(tmp, make_cookie(p1));
+ /* XXX The version check is not necessary according to RFC 2109 s. 10.1.1 */
         if (version > 0) {
             if (p1->flag & COO_PATH)
                 Strcat(tmp, Sprintf("; $Path=\"%s\"", p1->path->ptr));
@@ -226,12 +294,15 @@
            Str port, Str commentURL)
 {
     struct cookie *p;
- char *domainname = FQDN(pu->host);
+ char *domainname = fqdn(pu->host, pu->scheme);
     Str odomain = domain, opath = path;
     struct portlist *portlist = NULL;
+ int use_security = !(flag & COO_OVERRIDE);
+
+#define COOKIE_ERROR(err) if(!((err) & COO_OVERRIDE_OK) || use_security) return (err)
 
 #ifdef DEBUG
- fprintf(stderr, "host: [%s, %s] %d\n", pu->host, pu->file, flag);
+ fprintf(stderr, "host: [%s, %s] %d\n", pu->host, pu->file, flag & COO_SECURE);
     fprintf(stderr, "cookie: [%s=%s]\n", name->ptr, value->ptr);
     fprintf(stderr, "expires: [%s]\n", asctime(gmtime(&expires)));
     if (domain)
@@ -242,42 +313,63 @@
     if (port)
         fprintf(stderr, "port: [%s]\n", port->ptr);
 #endif /* DEBUG */
+ /* RFC 2109 s. 4.3.2 case 2; but this (no request-host) shouldn't happen */
     if (!domainname)
- return 1;
+ return COO_ENODOT;
 
     if (domain) {
         char *dp;
- char **sdomain;
-#if 0
- if (domain->ptr[0] != '.')
- return 1;
-#endif /* 0 */
+#if 1
+ /* RFC 2109 s. 4.3.2 case 2 subcase 2 (does not apply for version 0) */
+ if (version > 0 && domain->ptr[0] != '.')
+ COOKIE_ERROR(COO_ENOTV1DOM);
+#endif /* 1 */
+ /* RFC 2109 s. 4.3.2 case 2 subcase 1 */
         if (nodots(&domain->ptr[1], &domain->ptr[domain->length]))
- return 1;
- if (!(dp = domain_match(domainname, domain->ptr)))
- return 1;
+ COOKIE_ERROR(COO_ENODOT);
+ /* RFC 2109 s. 4.3.2 case 3, or version 0 "tail-matching" check */
+ if (!(dp = domain_or_tail_match(domainname, domain->ptr, version)))
+ COOKIE_ERROR(version? COO_EDOM: COO_ETAIL);
         if (version == 0) {
- for (sdomain = special_domain; *sdomain; sdomain++) {
- int offset = domain->length - strlen(*sdomain);
- if (offset >= 0 && strcasecmp(*sdomain, &domain->ptr[offset]) == 0)
- break;
+ /* count the number of dots */
+ int i;
+ int n = 0;
+ for (i = 0; i < domain->length; i += 1) {
+ if (domain->ptr[i] == '.')
+ n += 1;
+ }
+ if (n < 2) {
+ COOKIE_ERROR(COO_ESPECIAL);
+ } else if (n == 2) {
+ char **sdomain;
+ int ok = 0;
+ for (sdomain = special_domain; !ok && *sdomain; sdomain++) {
+ int offset = domain->length - strlen(*sdomain);
+ if (offset >= 0 && strcasecmp(*sdomain, &domain->ptr[offset]) == 0)
+ ok = 1;
+ }
+ if (!ok)
+ COOKIE_ERROR(COO_ESPECIAL);
             }
- if (!*sdomain && !nodots(domainname, dp))
- return 1;
         }
         else {
- if (!nodots(domainname, dp))
- return 1;
+ /* RFC 2109 s. 4.3.2 case 4 */
+ /* Invariant: dp contains matched domain */
+ if (!nodots(domainname, dp))
+ COOKIE_ERROR(COO_EBADHOST);
         }
     }
     if (path) {
- if (version > 0 && strncmp(path->ptr, pu->file, path->length) != 0)
- return 1;
+ /* RFC 2109 s. 4.3.2 case 1 */
+ /* XXX Why is the version 0 check here? */
+ if (version > 0 && strncmp(path->ptr, pu->file, path->length) != 0)
+ COOKIE_ERROR(COO_EPATH);
     }
     if (port) {
         portlist = make_portlist(port);
         if (portlist && !port_match(portlist, pu->port))
             return 1;
+ COOKIE_ERROR(COO_EPORT);
     }
 
     if (!domain)
@@ -514,7 +606,11 @@
         }
         if (p->commentURL) {
             Strcat_charp(src, "<tr><td width=\"80\"><b>CommentURL:</b></td><td>");
+ Strcat_charp(src, "<a href=\"");
+ Strcat_charp(src, htmlquote_str(p->commentURL->ptr));
+ Strcat_charp(src, "\">");
             Strcat_charp(src, htmlquote_str(p->commentURL->ptr));
+ Strcat_charp(src, "</a>");
             Strcat_charp(src, "</td></tr>");
         }
         if (tmp2[0]) {
@@ -524,6 +620,9 @@
                 Strcat_charp(src, " (Discard)");
             Strcat_charp(src, "</td></tr>");
         }
+ Strcat_charp(src, "<tr><td width=\"80\"><b>Version:</b></td><td>");
+ Strcat_charp(src, Sprintf("%d", p->version)->ptr);
+ Strcat_charp(src, "</td></tr><tr><td>");
         if (p->domain) {
             Strcat_charp(src, "<tr><td width=\"80\"><b>Domain:</b></td><td>");
             Strcat_charp(src, htmlquote_str(p->domain->ptr));
Common subdirectories: w3m-0.1.10.dist/doc and w3m-0.1.10-ja/doc
Common subdirectories: w3m-0.1.10.dist/doc-jp and w3m-0.1.10-ja/doc-jp
diff -u w3m-0.1.10.dist/etc.c w3m-0.1.10-ja/etc.c
--- w3m-0.1.10.dist/etc.c Tue Jun 6 01:39:13 2000
+++ w3m-0.1.10-ja/etc.c Thu Jul 6 15:37:13 2000
@@ -1080,6 +1080,7 @@
                     break;
                 switch (SSL_get_error(ss->handle, ss->status)) {
                 case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE: /* see SSL_get_error(3) */
                     continue;
                 default:
                     break;
diff -u w3m-0.1.10.dist/file.c w3m-0.1.10-ja/file.c
--- w3m-0.1.10.dist/file.c Tue Jun 6 01:54:35 2000
+++ w3m-0.1.10-ja/file.c Thu Jul 6 15:37:13 2000
@@ -122,6 +122,20 @@
 #define HR_RULE_WIDTH 1
 #endif /* not KANJI_SYMBOLS */
 
+#ifdef USE_COOKIE
+/* This array should be somewhere else */
+char *violations[COO_EMAX] = {
+ "tail match failed",
+ "wrong number of dots",
+ "RFC 2109 4.3.2 rule 1",
+ "RFC 2109 4.3.2 rule 2.1",
+ "RFC 2109 4.3.2 rule 2.2",
+ "RFC 2109 4.3.2 rule 3",
+ "RFC 2109 4.3.2 rule 4",
+ "RFC XXXX 4.3.2 rule 5"
+};
+#endif
+
 #ifndef STRCHR
 char *
 strchr(char *s, char c)
@@ -501,10 +515,18 @@
                 p++;
                 SKIP_BLANKS(p);
                 if (matchattr(p, "expires", 7, &tmp)) {
+ /* version 0 */
                     expires = mymktime(tmp->ptr);
                 }
                 else if (matchattr(p, "max-age", 7, &tmp)) {
+#if 0
                     expires = time(NULL) + atol(tmp->ptr);
+#else
+ long max_age = atol(tmp->ptr);
+ if (max_age == 0)
+ flag |= COO_DISCARD; /* RFC 2109 ss. 4.2.1, 4.2.2 */
+ expires = time(NULL) + max_age;
+#endif
                 }
                 else if (matchattr(p, "domain", 6, &tmp)) {
                     domain = tmp;
@@ -522,12 +544,15 @@
                     version = atoi(tmp->ptr);
                 }
                 else if (matchattr(p, "port", 4, &tmp)) {
+ /* version 1, Set-Cookie2 */
                     port = tmp;
                 }
                 else if (matchattr(p, "commentURL", 10, &tmp)) {
+ /* version 1, Set-Cookie2 */
                     commentURL = tmp;
                 }
                 else if (matchattr(p, "discard", 7, NULL)) {
+ /* version 1, Set-Cookie2 */
                     flag |= COO_DISCARD;
                 }
                 quoted = 0;
@@ -538,15 +563,49 @@
                 }
             }
             if (pu && name->length > 0) {
+ int err;
                 if (flag & COO_SECURE)
                     disp_message_nsec("Received a secured cookie", FALSE, 1, TRUE, FALSE);
                 else
                     disp_message_nsec(Sprintf("Received cookie: %s=%s",
                      name->ptr, value->ptr)->ptr, FALSE, 1, TRUE, FALSE);
- if (add_cookie(pu, name, value, expires, domain, path, flag,
- comment, version, port, commentURL))
- disp_message_nsec("This cookie was rejected "
- "to prevent security violation.", FALSE, 10, TRUE, FALSE);
+ err = add_cookie(pu, name, value, expires, domain, path, flag,
+ comment, version, port, commentURL);
+ if (err) {
+ /* XXX This should probably use some other, more friendly means of
+ inputting? */
+ char *ans = accept_bad_cookie == TRUE? "y": NULL;
+ if (fmInitialized && (err & COO_OVERRIDE_OK)
+ && accept_bad_cookie == PERHAPS)
+ {
+ /* XXX inputStr will crash if the line is close to COLS. Somehow
+ we need to make sure it doesn't crash. (impossible?) Really
+ need to fix it in linein.c. */
+ char *s = Sprintf("Accept bad cookie from %s for %s? (y or n) ",
+ pu->host, domain->ptr)->ptr;
+ int L = strlen(s);
+ if (L > COLS - 4)
+ s[COLS - 4] = '\0';
+ term_raw();
+ inputStr(s, FALSE);
+ }
+ if (ans == NULL || tolower(*ans) != 'y'
+ || (err = add_cookie(pu, name, value, expires, domain, path,
+ flag | COO_OVERRIDE, comment, version, port,
+ commentURL))) {
+ err = (err & ~COO_OVERRIDE_OK) - 1;
+ if (err >= 0 && err < COO_EMAX) {
+ disp_message_nsec(Sprintf("This cookie was rejected "
+ "to prevent security violation. [%s]",
+ violations[err])->ptr, FALSE, 10, TRUE, FALSE);
+ } else {
+ disp_message_nsec("This cookie was rejected "
+ "to prevent security violation.", FALSE, 10, TRUE, FALSE);
+ }
+ } else
+ disp_message_nsec(Sprintf("Accepting invalid cookie: %s=%s",
+ name->ptr,value->ptr)->ptr, FALSE, 1, TRUE, FALSE);
+ }
             }
         }
 #endif /* USE_COOKIE */
diff -u w3m-0.1.10.dist/fm.h w3m-0.1.10-ja/fm.h
--- w3m-0.1.10.dist/fm.h Tue Jun 6 01:54:35 2000
+++ w3m-0.1.10-ja/fm.h Thu Jul 6 15:37:13 2000
@@ -72,6 +72,10 @@
 #define FALSE 0
 #define TRUE 1
 
+#ifdef USE_COOKIE
+#define PERHAPS 2
+#endif
+
 #define INTERNAL_CODE 'E' /* use EUC-JP internally; do not change */
 
 #define SHELLBUFFERNAME "*Shellout*"
@@ -481,6 +485,21 @@
 #define COO_DOMAIN 4
 #define COO_PATH 8
 #define COO_DISCARD 16
+#define COO_OVERRIDE 32 /* user chose to override security checks */
+
+#define COO_OVERRIDE_OK 32 /* flag to specify that an error is overridable */
+ /* version 0 refers to the original cookie_spec.html */
+ /* version 1 refers to RFC 2109 */
+ /* version 1' refers to the Internet draft to obsolete RFC 2109 */
+#define COO_ETAIL (1 | COO_OVERRIDE_OK) /* tail match failed (version 0) */
+#define COO_ESPECIAL (2) /* special domain check failed (version 0) */
+#define COO_EPATH (3) /* Path attribute mismatch (version 1 case 1) */
+#define COO_ENODOT (4 | COO_OVERRIDE_OK) /* no embedded dots in Domain (version 1 case 2.1) */
+#define COO_ENOTV1DOM (5 | COO_OVERRIDE_OK) /* Domain does not start with a dot (version 1 case 2.2) */
+#define COO_EDOM (6 | COO_OVERRIDE_OK) /* domain-match failed (version 1 case 3) */
+#define COO_EBADHOST (7 | COO_OVERRIDE_OK) /* dot in matched host name in FQDN (version 1 case 4) */
+#define COO_EPORT (8) /* Port match failed (version 1' case 5) */
+#define COO_EMAX COO_EPORT
 #endif /* USE_COOKIE */
 
 typedef struct _Hist {
@@ -655,6 +674,7 @@
 global int default_use_cookie init(TRUE);
 global int use_cookie init(TRUE);
 global int accept_cookie init(FALSE);
+global int accept_bad_cookie init(FALSE);
 #endif /* USE_COOKIE */
 
 #ifdef VIEW_UNSEENOBJECTS
Common subdirectories: w3m-0.1.10.dist/gc and w3m-0.1.10-ja/gc
diff -u w3m-0.1.10.dist/rc.c w3m-0.1.10-ja/rc.c
--- w3m-0.1.10.dist/rc.c Mon Jun 5 07:17:04 2000
+++ w3m-0.1.10-ja/rc.c Thu Jul 6 16:07:21 2000
@@ -24,6 +24,17 @@
     struct sel_c *select;
 };
 
+#ifdef USE_COOKIE
+static char *badcookiestr[] = {
+ "0:discard",
+#if 0
+ "1:accept",
+#endif
+ "2:ask",
+ NULL,
+};
+#endif
+
 struct param_section {
     char *name;
     struct param_ptr *params;
@@ -97,6 +108,7 @@
 #define CMT_WRAP "折り返し検索"
 #define CMT_USECOOKIE "クッキーを使用する"
 #define CMT_ACCEPTCOOKIE "クッキーを受け付ける"
+#define CMT_ACCEPTBADCOOKIE "無効のクッキー" /*XXX FIXME (replace with real Japanese translation) */
 #define CMT_VIEW_UNSEENOBJECTS "背景画像等へのリンクを作る"
 #define CMT_BGEXTVIEW "外部ビューアをバックグラウンドで動かす"
 #define CMT_EXT_DIRLIST "ディレクトリリストに外部コマンドを使う"
@@ -163,6 +175,7 @@
 #define CMT_WRAP "Wrap search"
 #define CMT_USECOOKIE "Use Cookie"
 #define CMT_ACCEPTCOOKIE "Accept Cookie"
+#define CMT_ACCEPTBADCOOKIE "Invalid Cookie"
 #define CMT_VIEW_UNSEENOBJECTS "Display unseenobjects (e.g. bgimage) tag"
 #define CMT_BGEXTVIEW "Background an external viewer"
 #define CMT_EXT_DIRLIST "Use external program for directory listing"
@@ -302,6 +315,7 @@
 #ifdef USE_COOKIE
     {"use_cookie", P_INT, PI_ONOFF, (void *) &use_cookie, CMT_USECOOKIE, NULL},
     {"accept_cookie", P_INT, PI_ONOFF, (void *) &accept_cookie, CMT_ACCEPTCOOKIE, NULL},
+ {"accept_bad_cookie", P_INT, PI_SEL_C, (void*)&accept_bad_cookie, CMT_ACCEPTBADCOOKIE, &badcookiestr},
 #endif /* USE_COOKIE */
 #ifdef MOUSE
     {"use_mouse", P_INT, PI_ONOFF, (void *) &use_mouse, CMT_MOUSE, NULL},
@@ -706,12 +720,21 @@
 void
 parse_proxy()
 {
- if (non_null(HTTP_proxy))
+ if (non_null(HTTP_proxy)) {
         parseURL(HTTP_proxy, &HTTP_proxy_parsed, NULL);
- if (non_null(GOPHER_proxy))
+ if (HTTP_proxy_parsed.scheme != SCM_HTTP)
+ fprintf(stderr, "Warning: HTTP proxy scheme is not HTTP!\n");
+ }
+ if (non_null(GOPHER_proxy)) {
         parseURL(GOPHER_proxy, &GOPHER_proxy_parsed, NULL);
- if (non_null(FTP_proxy))
+ if (GOPHER_proxy_parsed.scheme != SCM_HTTP)
+ fprintf(stderr, "Warning: GOPHER proxy scheme is not HTTP!\n");
+ }
+ if (non_null(FTP_proxy)) {
         parseURL(FTP_proxy, &FTP_proxy_parsed, NULL);
+ if (FTP_proxy_parsed.scheme != SCM_HTTP)
+ fprintf(stderr, "Warning: FTP proxy scheme is not HTTP!\n");
+ }
     if (non_null(NO_proxy))
         set_no_proxy(NO_proxy);
 }
diff -u w3m-0.1.10.dist/rcparams.h w3m-0.1.10-ja/rcparams.h
--- w3m-0.1.10.dist/rcparams.h Mon Jun 5 07:17:04 2000
+++ w3m-0.1.10-ja/rcparams.h Thu Jul 6 15:37:13 2000
@@ -44,6 +44,7 @@
 global int WrapDefault init(FALSE);
 #ifdef USE_COOKIE
 global int use_cookie init(TRUE);
+global int accept_bad_cookie init(FALSE);
 #endif /* USE_COOKIE */
 
 /* params4 */
Common subdirectories: w3m-0.1.10.dist/scripts and w3m-0.1.10-ja/scripts
diff -u w3m-0.1.10.dist/url.c w3m-0.1.10-ja/url.c
--- w3m-0.1.10.dist/url.c Mon Jun 5 19:39:28 2000
+++ w3m-0.1.10-ja/url.c Thu Jul 6 17:54:51 2000
@@ -20,6 +20,12 @@
 #include "myctype.h"
 #include "regex.h"
 
+#ifdef USE_SSL
+#ifndef SSLEAY_VERSION_NUMBER
+#include <crypto.h> /* SSLEAY_VERSION_NUMBER may be here */
+#endif
+#endif
+
 #ifdef __WATT32__
 #define write(a,b,c) write_s(a,b,c)
 #endif /* __WATT32__ */
@@ -369,6 +375,8 @@
         bcopy((void *) &adr, (void *) &hostaddr.sin_addr, sizeof(long));
         hostaddr.sin_family = AF_INET;
         hostaddr.sin_port = s_port;
+ message(Sprintf("Connecting to %s\n", hostname)->ptr, 0, 0);
+ refresh();
         if (connect(sock, (struct sockaddr *) &hostaddr,
                     sizeof(struct sockaddr_in)) < 0) {
 #ifdef SOCK_DEBUG

-- 
Ambrose Li                945C 2CF7 001D 5F03 B026  375F C5CF A55C 9F10 8B0E
EDP Department (Toronto)                       Tel  +1  (1)416 321 0088 x272
Ming Pao Newspapers (Canada) Ltd               Fax  +1  (1)416 321 9663



This archive was generated by hypermail 2b29 : Wed Jul 19 2000 - 10:30:43 CDT