comparison libpurple/util.c @ 26162:0a19fa42f8ce

propagate from branch 'im.pidgin.pidgin' (head eeaad582dcb34b6753c78371c4aa03af92b095f5) to branch 'im.pidgin.soc.2008.yahoo' (head 182668e30410a6c12e970fad010f219ee6b59e73)
author Sulabh Mahajan <sulabh@soc.pidgin.im>
date Tue, 20 Jan 2009 17:44:36 +0000
parents 3d3376237a7c
children fb89c9f6e57a 43b721aa4b76
comparison
equal deleted inserted replaced
26161:90ffe6f71fa9 26162:0a19fa42f8ce
54 gboolean http11; 54 gboolean http11;
55 char *request; 55 char *request;
56 gsize request_written; 56 gsize request_written;
57 gboolean include_headers; 57 gboolean include_headers;
58 58
59 gboolean is_ssl;
60 PurpleSslConnection *ssl_connection;
59 PurpleProxyConnectData *connect_data; 61 PurpleProxyConnectData *connect_data;
60 int fd; 62 int fd;
61 guint inpa; 63 guint inpa;
62 64
63 gboolean got_headers; 65 gboolean got_headers;
981 const gchar *css_str = style; 983 const gchar *css_str = style;
982 const gchar *css_value_start; 984 const gchar *css_value_start;
983 const gchar *css_value_end; 985 const gchar *css_value_end;
984 gchar *tmp; 986 gchar *tmp;
985 gchar *ret; 987 gchar *ret;
988
989 g_return_val_if_fail(opt != NULL, NULL);
986 990
987 if (!css_str) 991 if (!css_str)
988 return NULL; 992 return NULL;
989 993
990 /* find the CSS property */ 994 /* find the CSS property */
1670 { 1674 {
1671 case 1: 1675 case 1:
1672 size = "xx-small"; 1676 size = "xx-small";
1673 break; 1677 break;
1674 case 2: 1678 case 2:
1675 size = "x-small"; 1679 size = "small";
1676 break; 1680 break;
1677 case 3: 1681 case 3:
1678 size = "small"; 1682 size = "medium";
1679 break; 1683 break;
1680 case 4: 1684 case 4:
1681 size = "medium"; 1685 size = "large";
1682 break; 1686 break;
1683 case 5: 1687 case 5:
1684 size = "large"; 1688 size = "x-large";
1685 break; 1689 break;
1686 case 6: 1690 case 6:
1687 size = "x-large";
1688 break;
1689 case 7: 1691 case 7:
1690 size = "xx-large"; 1692 size = "xx-large";
1691 break; 1693 break;
1692 default: 1694 default:
1693 break; 1695 break;
2388 guint z = 0; 2390 guint z = 0;
2389 gboolean appended = FALSE; 2391 gboolean appended = FALSE;
2390 gunichar c; 2392 gunichar c;
2391 char *tag; 2393 char *tag;
2392 2394
2395 g_return_val_if_fail(str != NULL, NULL);
2393 g_return_val_if_fail(x <= y, NULL); 2396 g_return_val_if_fail(x <= y, NULL);
2394 2397
2395 if (x == y) 2398 if (x == y)
2396 return g_strdup(""); 2399 return g_strdup("");
2397 2400
3510 */ 3513 */
3511 gboolean 3514 gboolean
3512 purple_url_parse(const char *url, char **ret_host, int *ret_port, 3515 purple_url_parse(const char *url, char **ret_host, int *ret_port,
3513 char **ret_path, char **ret_user, char **ret_passwd) 3516 char **ret_path, char **ret_user, char **ret_passwd)
3514 { 3517 {
3518 gboolean is_https = FALSE;
3515 char scan_info[255]; 3519 char scan_info[255];
3516 char port_str[6]; 3520 char port_str[6];
3517 int f; 3521 int f;
3518 const char *at, *slash; 3522 const char *at, *slash;
3519 const char *turl; 3523 const char *turl;
3533 turl += 7; 3537 turl += 7;
3534 url = turl; 3538 url = turl;
3535 } 3539 }
3536 else if ((turl = purple_strcasestr(url, "https://")) != NULL) 3540 else if ((turl = purple_strcasestr(url, "https://")) != NULL)
3537 { 3541 {
3542 is_https = TRUE;
3538 turl += 8; 3543 turl += 8;
3539 url = turl; 3544 url = turl;
3540 } 3545 }
3541 3546
3542 /* parse out authentication information if supplied */ 3547 /* parse out authentication information if supplied */
3573 { 3578 {
3574 g_snprintf(scan_info, sizeof(scan_info), 3579 g_snprintf(scan_info, sizeof(scan_info),
3575 "%%255[%s]/%%255[%s]", 3580 "%%255[%s]/%%255[%s]",
3576 addr_ctrl, page_ctrl); 3581 addr_ctrl, page_ctrl);
3577 f = sscanf(url, scan_info, host, path); 3582 f = sscanf(url, scan_info, host, path);
3578 g_snprintf(port_str, sizeof(port_str), "80"); 3583 /* Use the default port */
3584 if (is_https)
3585 g_snprintf(port_str, sizeof(port_str), "443");
3586 else
3587 g_snprintf(port_str, sizeof(port_str), "80");
3579 } 3588 }
3580 3589
3581 if (f == 0) 3590 if (f == 0)
3582 *host = '\0'; 3591 *host = '\0';
3583 3592
3612 g_free(error_message); 3621 g_free(error_message);
3613 purple_util_fetch_url_cancel(gfud); 3622 purple_util_fetch_url_cancel(gfud);
3614 } 3623 }
3615 3624
3616 static void url_fetch_connect_cb(gpointer url_data, gint source, const gchar *error_message); 3625 static void url_fetch_connect_cb(gpointer url_data, gint source, const gchar *error_message);
3626 static void ssl_url_fetch_connect_cb(gpointer data, PurpleSslConnection *ssl_connection, PurpleInputCondition cond);
3627 static void ssl_url_fetch_error_cb(PurpleSslConnection *ssl_connection, PurpleSslErrorType error, gpointer data);
3617 3628
3618 static gboolean 3629 static gboolean
3619 parse_redirect(const char *data, size_t data_len, 3630 parse_redirect(const char *data, size_t data_len,
3620 PurpleUtilFetchUrlData *gfud) 3631 PurpleUtilFetchUrlData *gfud)
3621 { 3632 {
3678 gfud->url = new_url; 3689 gfud->url = new_url;
3679 gfud->full = full; 3690 gfud->full = full;
3680 g_free(gfud->request); 3691 g_free(gfud->request);
3681 gfud->request = NULL; 3692 gfud->request = NULL;
3682 3693
3683 purple_input_remove(gfud->inpa); 3694 if (gfud->is_ssl) {
3684 gfud->inpa = 0; 3695 gfud->is_ssl = FALSE;
3685 close(gfud->fd); 3696 purple_ssl_close(gfud->ssl_connection);
3686 gfud->fd = -1; 3697 gfud->ssl_connection = NULL;
3698 } else {
3699 purple_input_remove(gfud->inpa);
3700 gfud->inpa = 0;
3701 close(gfud->fd);
3702 gfud->fd = -1;
3703 }
3687 gfud->request_written = 0; 3704 gfud->request_written = 0;
3688 gfud->len = 0; 3705 gfud->len = 0;
3689 gfud->data_len = 0; 3706 gfud->data_len = 0;
3690 3707
3691 g_free(gfud->website.user); 3708 g_free(gfud->website.user);
3693 g_free(gfud->website.address); 3710 g_free(gfud->website.address);
3694 g_free(gfud->website.page); 3711 g_free(gfud->website.page);
3695 purple_url_parse(new_url, &gfud->website.address, &gfud->website.port, 3712 purple_url_parse(new_url, &gfud->website.address, &gfud->website.port,
3696 &gfud->website.page, &gfud->website.user, &gfud->website.passwd); 3713 &gfud->website.page, &gfud->website.user, &gfud->website.passwd);
3697 3714
3698 gfud->connect_data = purple_proxy_connect(NULL, NULL, 3715 if (purple_strcasestr(new_url, "https://") != NULL) {
3699 gfud->website.address, gfud->website.port, 3716 gfud->is_ssl = TRUE;
3700 url_fetch_connect_cb, gfud); 3717 gfud->ssl_connection = purple_ssl_connect(NULL,
3701 3718 gfud->website.address, gfud->website.port,
3702 if (gfud->connect_data == NULL) 3719 ssl_url_fetch_connect_cb, ssl_url_fetch_error_cb, gfud);
3720 } else {
3721 gfud->connect_data = purple_proxy_connect(NULL, NULL,
3722 gfud->website.address, gfud->website.port,
3723 url_fetch_connect_cb, gfud);
3724 }
3725
3726 if (gfud->ssl_connection == NULL && gfud->connect_data == NULL)
3703 { 3727 {
3704 purple_util_fetch_url_error(gfud, _("Unable to connect to %s"), 3728 purple_util_fetch_url_error(gfud, _("Unable to connect to %s"),
3705 gfud->website.address); 3729 gfud->website.address);
3706 } 3730 }
3707 3731
3758 int len; 3782 int len;
3759 char buf[4096]; 3783 char buf[4096];
3760 char *data_cursor; 3784 char *data_cursor;
3761 gboolean got_eof = FALSE; 3785 gboolean got_eof = FALSE;
3762 3786
3763 while((len = read(source, buf, sizeof(buf))) > 0) { 3787 /*
3764 3788 * Read data in a loop until we can't read any more! This is a
3789 * little confusing because we read using a different function
3790 * depending on whether the socket is ssl or cleartext.
3791 */
3792 while ((gfud->is_ssl && ((len = purple_ssl_read(gfud->ssl_connection, buf, sizeof(buf))) > 0)) ||
3793 (!gfud->is_ssl && (len = read(source, buf, sizeof(buf))) > 0))
3794 {
3765 if(gfud->max_len != -1 && (gfud->len + len) > gfud->max_len) { 3795 if(gfud->max_len != -1 && (gfud->len + len) > gfud->max_len) {
3766 purple_util_fetch_url_error(gfud, _("Error reading from %s: response too long (%d bytes limit)"), 3796 purple_util_fetch_url_error(gfud, _("Error reading from %s: response too long (%d bytes limit)"),
3767 gfud->website.address, gfud->max_len); 3797 gfud->website.address, gfud->max_len);
3768 return; 3798 return;
3769 } 3799 }
3879 gfud->callback(gfud, gfud->user_data, gfud->webdata, gfud->len, NULL); 3909 gfud->callback(gfud, gfud->user_data, gfud->webdata, gfud->len, NULL);
3880 purple_util_fetch_url_cancel(gfud); 3910 purple_util_fetch_url_cancel(gfud);
3881 } 3911 }
3882 } 3912 }
3883 3913
3914 static void ssl_url_fetch_recv_cb(gpointer data, PurpleSslConnection *ssl_connection, PurpleInputCondition cond)
3915 {
3916 url_fetch_recv_cb(data, -1, cond);
3917 }
3918
3919 /*
3920 * This function is called when the socket is available to be written
3921 * to.
3922 *
3923 * @param source The file descriptor that can be written to. This can
3924 * be an http connection or it can be the SSL connection of an
3925 * https request. So be careful what you use it for! If it's
3926 * an https request then use purple_ssl_write() instead of
3927 * writing to it directly.
3928 */
3884 static void 3929 static void
3885 url_fetch_send_cb(gpointer data, gint source, PurpleInputCondition cond) 3930 url_fetch_send_cb(gpointer data, gint source, PurpleInputCondition cond)
3886 { 3931 {
3887 PurpleUtilFetchUrlData *gfud; 3932 PurpleUtilFetchUrlData *gfud;
3888 int len, total_len; 3933 int len, total_len;
3889 3934
3890 gfud = data; 3935 gfud = data;
3891 3936
3892 total_len = strlen(gfud->request); 3937 if (gfud->request == NULL)
3893 3938 {
3894 len = write(gfud->fd, gfud->request + gfud->request_written, 3939 /* Host header is not forbidden in HTTP/1.0 requests, and HTTP/1.1
3895 total_len - gfud->request_written); 3940 * clients must know how to handle the "chunked" transfer encoding.
3896 3941 * Purple doesn't know how to handle "chunked", so should always send
3897 if (len < 0 && errno == EAGAIN) 3942 * the Host header regardless, to get around some observed problems
3898 return; 3943 */
3899 else if (len < 0) {
3900 purple_util_fetch_url_error(gfud, _("Error writing to %s: %s"),
3901 gfud->website.address, g_strerror(errno));
3902 return;
3903 }
3904 gfud->request_written += len;
3905
3906 if (gfud->request_written < total_len)
3907 return;
3908
3909 /* We're done writing our request, now start reading the response */
3910 purple_input_remove(gfud->inpa);
3911 gfud->inpa = purple_input_add(gfud->fd, PURPLE_INPUT_READ, url_fetch_recv_cb,
3912 gfud);
3913 }
3914
3915 static void
3916 url_fetch_connect_cb(gpointer url_data, gint source, const gchar *error_message)
3917 {
3918 PurpleUtilFetchUrlData *gfud;
3919
3920 gfud = url_data;
3921 gfud->connect_data = NULL;
3922
3923 if (source == -1)
3924 {
3925 purple_util_fetch_url_error(gfud, _("Unable to connect to %s: %s"),
3926 (gfud->website.address ? gfud->website.address : ""), error_message);
3927 return;
3928 }
3929
3930 gfud->fd = source;
3931
3932 if (!gfud->request) {
3933 if (gfud->user_agent) { 3944 if (gfud->user_agent) {
3934 /* Host header is not forbidden in HTTP/1.0 requests, and HTTP/1.1
3935 * clients must know how to handle the "chunked" transfer encoding.
3936 * Purple doesn't know how to handle "chunked", so should always send
3937 * the Host header regardless, to get around some observed problems
3938 */
3939 gfud->request = g_strdup_printf( 3945 gfud->request = g_strdup_printf(
3940 "GET %s%s HTTP/%s\r\n" 3946 "GET %s%s HTTP/%s\r\n"
3941 "Connection: close\r\n" 3947 "Connection: close\r\n"
3942 "User-Agent: %s\r\n" 3948 "User-Agent: %s\r\n"
3943 "Accept: */*\r\n" 3949 "Accept: */*\r\n"
3960 } 3966 }
3961 } 3967 }
3962 3968
3963 purple_debug_misc("util", "Request: '%s'\n", gfud->request); 3969 purple_debug_misc("util", "Request: '%s'\n", gfud->request);
3964 3970
3971 total_len = strlen(gfud->request);
3972
3973 if (gfud->is_ssl)
3974 len = purple_ssl_write(gfud->ssl_connection, gfud->request + gfud->request_written,
3975 total_len - gfud->request_written);
3976 else
3977 len = write(gfud->fd, gfud->request + gfud->request_written,
3978 total_len - gfud->request_written);
3979
3980 if (len < 0 && errno == EAGAIN)
3981 return;
3982 else if (len < 0) {
3983 purple_util_fetch_url_error(gfud, _("Error writing to %s: %s"),
3984 gfud->website.address, g_strerror(errno));
3985 return;
3986 }
3987 gfud->request_written += len;
3988
3989 if (gfud->request_written < total_len)
3990 return;
3991
3992 /* We're done writing our request, now start reading the response */
3993 if (gfud->is_ssl) {
3994 purple_input_remove(gfud->inpa);
3995 gfud->inpa = 0;
3996 purple_ssl_input_add(gfud->ssl_connection, ssl_url_fetch_recv_cb, gfud);
3997 } else {
3998 purple_input_remove(gfud->inpa);
3999 gfud->inpa = purple_input_add(gfud->fd, PURPLE_INPUT_READ, url_fetch_recv_cb,
4000 gfud);
4001 }
4002 }
4003
4004 static void
4005 url_fetch_connect_cb(gpointer url_data, gint source, const gchar *error_message)
4006 {
4007 PurpleUtilFetchUrlData *gfud;
4008
4009 gfud = url_data;
4010 gfud->connect_data = NULL;
4011
4012 if (source == -1)
4013 {
4014 purple_util_fetch_url_error(gfud, _("Unable to connect to %s: %s"),
4015 (gfud->website.address ? gfud->website.address : ""), error_message);
4016 return;
4017 }
4018
4019 gfud->fd = source;
4020
3965 gfud->inpa = purple_input_add(source, PURPLE_INPUT_WRITE, 4021 gfud->inpa = purple_input_add(source, PURPLE_INPUT_WRITE,
3966 url_fetch_send_cb, gfud); 4022 url_fetch_send_cb, gfud);
3967 url_fetch_send_cb(gfud, source, PURPLE_INPUT_WRITE); 4023 url_fetch_send_cb(gfud, source, PURPLE_INPUT_WRITE);
4024 }
4025
4026 static void ssl_url_fetch_connect_cb(gpointer data, PurpleSslConnection *ssl_connection, PurpleInputCondition cond)
4027 {
4028 PurpleUtilFetchUrlData *gfud;
4029
4030 gfud = data;
4031
4032 gfud->inpa = purple_input_add(ssl_connection->fd, PURPLE_INPUT_WRITE,
4033 url_fetch_send_cb, gfud);
4034 url_fetch_send_cb(gfud, ssl_connection->fd, PURPLE_INPUT_WRITE);
4035 }
4036
4037 static void ssl_url_fetch_error_cb(PurpleSslConnection *ssl_connection, PurpleSslErrorType error, gpointer data)
4038 {
4039 PurpleUtilFetchUrlData *gfud;
4040
4041 gfud = data;
4042 gfud->ssl_connection = NULL;
4043
4044 purple_util_fetch_url_error(gfud, _("Unable to connect to %s: %s"),
4045 (gfud->website.address ? gfud->website.address : ""),
4046 purple_ssl_strerror(error));
3968 } 4047 }
3969 4048
3970 PurpleUtilFetchUrlData * 4049 PurpleUtilFetchUrlData *
3971 purple_util_fetch_url_request(const char *url, gboolean full, 4050 purple_util_fetch_url_request(const char *url, gboolean full,
3972 const char *user_agent, gboolean http11, 4051 const char *user_agent, gboolean http11,
3975 { 4054 {
3976 return purple_util_fetch_url_request_len(url, full, 4055 return purple_util_fetch_url_request_len(url, full,
3977 user_agent, http11, 4056 user_agent, http11,
3978 request, include_headers, -1, 4057 request, include_headers, -1,
3979 callback, user_data); 4058 callback, user_data);
3980 }
3981
3982 static gboolean
3983 url_fetch_connect_failed(gpointer data)
3984 {
3985 url_fetch_connect_cb(data, -1, "");
3986 return FALSE;
3987 } 4059 }
3988 4060
3989 PurpleUtilFetchUrlData * 4061 PurpleUtilFetchUrlData *
3990 purple_util_fetch_url_request_len(const char *url, gboolean full, 4062 purple_util_fetch_url_request_len(const char *url, gboolean full,
3991 const char *user_agent, gboolean http11, 4063 const char *user_agent, gboolean http11,
4015 gfud->max_len = max_len; 4087 gfud->max_len = max_len;
4016 4088
4017 purple_url_parse(url, &gfud->website.address, &gfud->website.port, 4089 purple_url_parse(url, &gfud->website.address, &gfud->website.port,
4018 &gfud->website.page, &gfud->website.user, &gfud->website.passwd); 4090 &gfud->website.page, &gfud->website.user, &gfud->website.passwd);
4019 4091
4020 gfud->connect_data = purple_proxy_connect(NULL, NULL, 4092 if (purple_strcasestr(url, "https://") != NULL) {
4021 gfud->website.address, gfud->website.port, 4093 gfud->is_ssl = TRUE;
4022 url_fetch_connect_cb, gfud); 4094 gfud->ssl_connection = purple_ssl_connect(NULL,
4023 4095 gfud->website.address, gfud->website.port,
4024 if (gfud->connect_data == NULL) 4096 ssl_url_fetch_connect_cb, ssl_url_fetch_error_cb, gfud);
4025 { 4097 } else {
4026 /* Trigger the connect_cb asynchronously. */ 4098 gfud->connect_data = purple_proxy_connect(NULL, NULL,
4027 purple_timeout_add(10, url_fetch_connect_failed, gfud); 4099 gfud->website.address, gfud->website.port,
4100 url_fetch_connect_cb, gfud);
4101 }
4102
4103 if (gfud->ssl_connection == NULL && gfud->connect_data == NULL)
4104 {
4105 purple_util_fetch_url_error(gfud, _("Unable to connect to %s"),
4106 gfud->website.address);
4107 return NULL;
4028 } 4108 }
4029 4109
4030 return gfud; 4110 return gfud;
4031 } 4111 }
4032 4112
4033 void 4113 void
4034 purple_util_fetch_url_cancel(PurpleUtilFetchUrlData *gfud) 4114 purple_util_fetch_url_cancel(PurpleUtilFetchUrlData *gfud)
4035 { 4115 {
4116 if (gfud->ssl_connection != NULL)
4117 purple_ssl_close(gfud->ssl_connection);
4118
4036 if (gfud->connect_data != NULL) 4119 if (gfud->connect_data != NULL)
4037 purple_proxy_connect_cancel(gfud->connect_data); 4120 purple_proxy_connect_cancel(gfud->connect_data);
4038 4121
4039 if (gfud->inpa > 0) 4122 if (gfud->inpa > 0)
4040 purple_input_remove(gfud->inpa); 4123 purple_input_remove(gfud->inpa);
4143 purple_email_is_valid(const char *address) 4226 purple_email_is_valid(const char *address)
4144 { 4227 {
4145 const char *c, *domain; 4228 const char *c, *domain;
4146 static char *rfc822_specials = "()<>@,;:\\\"[]"; 4229 static char *rfc822_specials = "()<>@,;:\\\"[]";
4147 4230
4231 g_return_val_if_fail(address != NULL, FALSE);
4232
4148 /* first we validate the name portion (name@domain) (rfc822)*/ 4233 /* first we validate the name portion (name@domain) (rfc822)*/
4149 for (c = address; *c; c++) { 4234 for (c = address; *c; c++) {
4150 if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == '\"')) { 4235 if (*c == '\"' && (c == address || *(c - 1) == '.' || *(c - 1) == '\"')) {
4151 while (*++c) { 4236 while (*++c) {
4152 if (*c == '\\') { 4237 if (*c == '\\') {
4191 gboolean 4276 gboolean
4192 purple_ip_address_is_valid(const char *ip) 4277 purple_ip_address_is_valid(const char *ip)
4193 { 4278 {
4194 int c, o1, o2, o3, o4; 4279 int c, o1, o2, o3, o4;
4195 char end; 4280 char end;
4281
4282 g_return_val_if_fail(ip != NULL, FALSE);
4283
4196 c = sscanf(ip, "%d.%d.%d.%d%c", &o1, &o2, &o3, &o4, &end); 4284 c = sscanf(ip, "%d.%d.%d.%d%c", &o1, &o2, &o3, &o4, &end);
4197 if (c != 4 || o1 < 0 || o1 > 255 || o2 < 0 || o2 > 255 || o3 < 0 || o3 > 255 || o4 < 0 || o4 > 255) 4285 if (c != 4 || o1 < 0 || o1 > 255 || o2 < 0 || o2 > 255 || o3 < 0 || o3 > 255 || o4 < 0 || o4 > 255)
4198 return FALSE; 4286 return FALSE;
4199 return TRUE; 4287 return TRUE;
4200 } 4288 }
4480 /* previously conversation::find_nick() */ 4568 /* previously conversation::find_nick() */
4481 gboolean 4569 gboolean
4482 purple_utf8_has_word(const char *haystack, const char *needle) 4570 purple_utf8_has_word(const char *haystack, const char *needle)
4483 { 4571 {
4484 char *hay, *pin, *p; 4572 char *hay, *pin, *p;
4573 const char *start, *prev_char;
4574 gunichar before, after;
4485 int n; 4575 int n;
4486 gboolean ret = FALSE; 4576 gboolean ret = FALSE;
4487 4577
4488 hay = g_utf8_strdown(haystack, -1); 4578 start = hay = g_utf8_strdown(haystack, -1);
4489 4579
4490 pin = g_utf8_strdown(needle, -1); 4580 pin = g_utf8_strdown(needle, -1);
4491 n = strlen(pin); 4581 n = strlen(pin);
4492 4582
4493 if ((p = strstr(hay, pin)) != NULL) { 4583 while ((p = strstr(start, pin)) != NULL) {
4494 if ((p == hay || !isalnum(*(p - 1))) && !isalnum(*(p + n))) { 4584 prev_char = g_utf8_find_prev_char(hay, p);
4585 before = -2;
4586 if (prev_char) {
4587 before = g_utf8_get_char(prev_char);
4588 }
4589 after = g_utf8_get_char_validated(p + n, - 1);
4590
4591 if ((p == hay ||
4592 /* The character before is a reasonable guess for a word boundary
4593 ("!g_unichar_isalnum()" is not a valid way to determine word
4594 boundaries, but it is the only reasonable thing to do here),
4595 and isn't the '&' from a "&amp;" or some such entity*/
4596 (before != -2 && !g_unichar_isalnum(before) && *(p - 1) != '&'))
4597 && after != -2 && !g_unichar_isalnum(after)) {
4495 ret = TRUE; 4598 ret = TRUE;
4496 } 4599 break;
4600 }
4601 start = p + 1;
4497 } 4602 }
4498 4603
4499 g_free(pin); 4604 g_free(pin);
4500 g_free(hay); 4605 g_free(hay);
4501 4606