Mercurial > pidgin
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 "&" 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 |