comparison libpurple/protocols/oscar/oscar.c @ 25947:4b8c4870b13a

propagate from branch 'im.pidgin.pidgin.next.minor' (head 7305b29db7bd00d3261f348c71674c93aa31b327) to branch 'im.pidgin.pidgin' (head d8c03c68d591d9392607d954942ee58b8618d946)
author Elliott Sales de Andrade <qulogic@pidgin.im>
date Mon, 02 Mar 2009 04:18:40 +0000
parents 8c8948b9f602 937d832f4d7f
children cc9fb95cede5
comparison
equal deleted inserted replaced
25946:8998ca47e6d0 25947:4b8c4870b13a
2075 g_free(host); 2075 g_free(host);
2076 2076
2077 return 1; 2077 return 1;
2078 } 2078 }
2079 2079
2080 static gboolean purple_requesticqstatusnote(gpointer data)
2081 {
2082 PurpleConnection *gc = data;
2083 OscarData *od = purple_connection_get_protocol_data(gc);
2084
2085 while (od->statusnotes_queue != NULL)
2086 {
2087 char *bn;
2088 struct aim_ssi_item *ssi_item;
2089 aim_tlv_t *note_hash;
2090
2091 bn = od->statusnotes_queue->data;
2092
2093 ssi_item = aim_ssi_itemlist_finditem(od->ssi.local,
2094 NULL, bn, AIM_SSI_TYPE_BUDDY);
2095 if (ssi_item != NULL)
2096 {
2097 note_hash = aim_tlv_gettlv(ssi_item->data, 0x015c, 1);
2098 if (note_hash != NULL) {
2099 aim_icq_getstatusnote(od, bn, note_hash->value, note_hash->length);
2100 }
2101 }
2102
2103 od->statusnotes_queue = g_slist_remove(od->statusnotes_queue, bn);
2104 g_free(bn);
2105 }
2106
2107 od->statusnotes_queue_timer = 0;
2108 return FALSE;
2109 }
2110
2111 2080
2112 static int purple_parse_oncoming(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...) 2081 static int purple_parse_oncoming(OscarData *od, FlapConnection *conn, FlapFrame *fr, ...)
2113 { 2082 {
2114 PurpleConnection *gc; 2083 PurpleConnection *gc;
2115 PurpleAccount *account; 2084 PurpleAccount *account;
2118 int type = 0; 2087 int type = 0;
2119 gboolean buddy_is_away = FALSE; 2088 gboolean buddy_is_away = FALSE;
2120 const char *status_id; 2089 const char *status_id;
2121 va_list ap; 2090 va_list ap;
2122 aim_userinfo_t *info; 2091 aim_userinfo_t *info;
2092 char *message = NULL;
2093 char *itmsurl = NULL;
2094 char *tmp;
2095 const char *tmp2;
2123 2096
2124 gc = od->gc; 2097 gc = od->gc;
2125 account = purple_connection_get_account(gc); 2098 account = purple_connection_get_account(gc);
2126 2099
2127 va_start(ap, fr); 2100 va_start(ap, fr);
2172 purple_prpl_got_user_status(account, info->bn, OSCAR_STATUS_ID_MOBILE, NULL); 2145 purple_prpl_got_user_status(account, info->bn, OSCAR_STATUS_ID_MOBILE, NULL);
2173 } else { 2146 } else {
2174 purple_prpl_got_user_status_deactive(account, info->bn, OSCAR_STATUS_ID_MOBILE); 2147 purple_prpl_got_user_status_deactive(account, info->bn, OSCAR_STATUS_ID_MOBILE);
2175 } 2148 }
2176 2149
2177 if (strcmp(status_id, OSCAR_STATUS_ID_AVAILABLE) == 0) 2150 if (info->status != NULL && info->status[0] != '\0')
2178 { 2151 /* Grab the available message */
2179 char *message = NULL; 2152 message = oscar_encoding_to_utf8(account, info->status_encoding,
2180 char *itmsurl = NULL; 2153 info->status, info->status_len);
2181 char *tmp; 2154
2182 const char *tmp2; 2155 tmp2 = tmp = (message ? g_markup_escape_text(message, -1) : NULL);
2183 2156
2184 if (info->status != NULL && info->status[0] != '\0') 2157 if (strcmp(status_id, OSCAR_STATUS_ID_AVAILABLE) == 0) {
2185 /* Grab the available message */
2186 message = oscar_encoding_to_utf8(account, info->status_encoding,
2187 info->status, info->status_len);
2188
2189 if (info->itmsurl_encoding && info->itmsurl && info->itmsurl_len) 2158 if (info->itmsurl_encoding && info->itmsurl && info->itmsurl_len)
2190 /* Grab the iTunes Music Store URL */ 2159 /* Grab the iTunes Music Store URL */
2191 itmsurl = oscar_encoding_to_utf8(account, info->itmsurl_encoding, 2160 itmsurl = oscar_encoding_to_utf8(account, info->itmsurl_encoding,
2192 info->itmsurl, info->itmsurl_len); 2161 info->itmsurl, info->itmsurl_len);
2193
2194 tmp2 = tmp = (message ? g_markup_escape_text(message, -1) : NULL);
2195 2162
2196 if (tmp2 == NULL && itmsurl != NULL) 2163 if (tmp2 == NULL && itmsurl != NULL)
2164 /*
2165 * The message can't be NULL because NULL means it was the
2166 * last attribute, so the itmsurl would get ignored below.
2167 */
2197 tmp2 = ""; 2168 tmp2 = "";
2198 2169
2199 purple_prpl_got_user_status(account, info->bn, status_id, 2170 purple_prpl_got_user_status(account, info->bn, status_id,
2200 "message", tmp2, "itmsurl", itmsurl, NULL); 2171 "message", tmp2, "itmsurl", itmsurl, NULL);
2201 g_free(tmp);
2202
2203 g_free(message);
2204 g_free(itmsurl);
2205 } 2172 }
2206 else 2173 else
2207 { 2174 purple_prpl_got_user_status(account, info->bn, status_id, "message", tmp2, NULL);
2208 PurpleBuddy *b = purple_find_buddy(account, info->bn); 2175
2209 PurplePresence *presence = purple_buddy_get_presence(b); 2176 g_free(tmp);
2210 PurpleStatus *old_status = purple_presence_get_active_status(presence); 2177
2211 PurpleStatus *new_status = purple_presence_get_status(presence, status_id); 2178 g_free(message);
2212 2179 g_free(itmsurl);
2213 /* If our status_id would change with this update, pass it to the core.
2214 * However, if our status_id would not change, do nothing, as we would clear out any existing
2215 * attributes on the status prematurely. purple_got_infoblock() will update the message as needed.
2216 */
2217 if (old_status != new_status)
2218 purple_prpl_got_user_status(account, info->bn, status_id, NULL);
2219 }
2220 2180
2221 /* Login time stuff */ 2181 /* Login time stuff */
2222 if (info->present & AIM_USERINFO_PRESENT_ONLINESINCE) 2182 if (info->present & AIM_USERINFO_PRESENT_ONLINESINCE)
2223 signon = info->onlinesince; 2183 signon = info->onlinesince;
2224 else if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN) 2184 else if (info->present & AIM_USERINFO_PRESENT_SESSIONLEN)
2267 g_strdup(purple_normalize(account, info->bn))); 2227 g_strdup(purple_normalize(account, info->bn)));
2268 purple_icons_fetch(gc); 2228 purple_icons_fetch(gc);
2269 } 2229 }
2270 } 2230 }
2271 g_free(b16); 2231 g_free(b16);
2272 }
2273
2274 /*
2275 * If we didn't receive a status message with the status change,
2276 * or if the message is empty, and we have a note hash, then
2277 * query the ICQ6 status note.
2278 *
2279 * TODO: We should probably always query the status note regardless
2280 * of whether they have a status message set, and we should
2281 * figure out a way to display both the status note and the
2282 * status message at the same time.
2283 */
2284 if (info->status == NULL || info->status[0] == '\0')
2285 {
2286 struct aim_ssi_item *ssi_item;
2287 aim_tlv_t *note_hash;
2288
2289 ssi_item = aim_ssi_itemlist_finditem(od->ssi.local,
2290 NULL, info->bn, AIM_SSI_TYPE_BUDDY);
2291 if (ssi_item != NULL)
2292 {
2293 note_hash = aim_tlv_gettlv(ssi_item->data, 0x015c, 1);
2294 if (note_hash != NULL) {
2295 /* We do automatic rate limiting at the FLAP level, so
2296 * a flood of requests won't disconnect us. However,
2297 * it WOULD mean that we would have to wait a
2298 * potentially long time to be able to message in real
2299 * time again. Also, since we're requesting with every
2300 * purple_parse_oncoming() call, which often come in
2301 * groups, we should coalesce to do only one lookup per
2302 * buddy.
2303 */
2304 if (od->statusnotes_queue == NULL ||
2305 g_slist_find_custom(od->statusnotes_queue, info->bn, (GCompareFunc)strcmp) == NULL)
2306 {
2307 od->statusnotes_queue = g_slist_prepend(od->statusnotes_queue,
2308 g_strdup(info->bn));
2309
2310 if (od->statusnotes_queue_timer > 0)
2311 purple_timeout_remove(od->statusnotes_queue_timer);
2312 od->statusnotes_queue_timer = purple_timeout_add_seconds(3,
2313 purple_requesticqstatusnote, gc);
2314 }
2315 }
2316 }
2317 } 2232 }
2318 2233
2319 return 1; 2234 return 1;
2320 } 2235 }
2321 2236
4516 msg = g_string_append_len(msg, data->str, data->len); 4431 msg = g_string_append_len(msg, data->str, data->len);
4517 msg = g_string_append(msg, "</BINARY>"); 4432 msg = g_string_append(msg, "</BINARY>");
4518 } 4433 }
4519 g_string_free(data, TRUE); 4434 g_string_free(data, TRUE);
4520 4435
4521 peer_odc_send_im(conn, msg->str, msg->len, charset, imflags); 4436 peer_odc_send_im(conn, msg->str, msg->len, charset, (imflags & PURPLE_MESSAGE_AUTO_RESP));
4522 g_string_free(msg, TRUE); 4437 g_string_free(msg, TRUE);
4523 } 4438 }
4524 4439
4525 int 4440 int
4526 oscar_send_im(PurpleConnection *gc, const char *name, const char *message, PurpleMessageFlags imflags) 4441 oscar_send_im(PurpleConnection *gc, const char *name, const char *message, PurpleMessageFlags imflags)
4556 4471
4557 conn = peer_connection_find_by_type(od, name, OSCAR_CAPABILITY_DIRECTIM); 4472 conn = peer_connection_find_by_type(od, name, OSCAR_CAPABILITY_DIRECTIM);
4558 if ((conn != NULL) && (conn->ready)) 4473 if ((conn != NULL) && (conn->ready))
4559 { 4474 {
4560 /* If we're directly connected, send a direct IM */ 4475 /* If we're directly connected, send a direct IM */
4476 purple_debug_info("oscar", "Sending direct IM with flags %i", imflags);
4561 purple_odc_send_im(conn, tmp1, imflags); 4477 purple_odc_send_im(conn, tmp1, imflags);
4562 } else { 4478 } else {
4563 struct buddyinfo *bi; 4479 struct buddyinfo *bi;
4564 struct aim_sendimext_args args; 4480 struct aim_sendimext_args args;
4565 PurpleConversation *conv; 4481 PurpleConversation *conv;
4877 4793
4878 status_html = purple_status_get_attr_string(status, "message"); 4794 status_html = purple_status_get_attr_string(status, "message");
4879 if (status_html != NULL) 4795 if (status_html != NULL)
4880 { 4796 {
4881 status_text = purple_markup_strip_html(status_html); 4797 status_text = purple_markup_strip_html(status_html);
4882 /* If the status_text is longer than 60 character then truncate it */ 4798 /* If the status_text is longer than 251 characters then truncate it */
4883 if (strlen(status_text) > MAXAVAILMSGLEN) 4799 if (strlen(status_text) > MAXAVAILMSGLEN)
4884 { 4800 {
4885 char *tmp = g_utf8_find_prev_char(status_text, &status_text[MAXAVAILMSGLEN - 2]); 4801 char *tmp = g_utf8_find_prev_char(status_text, &status_text[MAXAVAILMSGLEN - 2]);
4886 strcpy(tmp, "..."); 4802 strcpy(tmp, "...");
4887 } 4803 }
4894 /* This is needed for us to un-set any previous away message. */ 4810 /* This is needed for us to un-set any previous away message. */
4895 away = g_strdup(""); 4811 away = g_strdup("");
4896 } 4812 }
4897 else 4813 else
4898 { 4814 {
4815 char *status_text = NULL;
4816
4899 htmlaway = purple_status_get_attr_string(status, "message"); 4817 htmlaway = purple_status_get_attr_string(status, "message");
4900 if ((htmlaway == NULL) || (*htmlaway == '\0')) 4818 if ((htmlaway == NULL) || (*htmlaway == '\0'))
4901 htmlaway = purple_status_type_get_name(status_type); 4819 htmlaway = purple_status_type_get_name(status_type);
4820
4821 /* ICQ 6.x seems to use an available message for all statuses so set one */
4822 if (od->icq)
4823 {
4824 status_text = purple_markup_strip_html(htmlaway);
4825 /* If the status_text is longer than 251 characters then truncate it */
4826 if (strlen(status_text) > MAXAVAILMSGLEN)
4827 {
4828 char *tmp = g_utf8_find_prev_char(status_text, &status_text[MAXAVAILMSGLEN - 2]);
4829 strcpy(tmp, "...");
4830 }
4831 aim_srv_setextrainfo(od, FALSE, 0, TRUE, status_text, NULL);
4832 }
4833 g_free(status_text);
4834
4835 /* Set a proper away message for icq too so that they work for old third party clients */
4836
4902 away = purple_prpl_oscar_convert_to_infotext(htmlaway, &awaylen, &away_encoding); 4837 away = purple_prpl_oscar_convert_to_infotext(htmlaway, &awaylen, &away_encoding);
4903 4838
4904 if (awaylen > od->rights.maxawaymsglen) 4839 if (awaylen > od->rights.maxawaymsglen)
4905 { 4840 {
4906 gchar *errstr; 4841 gchar *errstr;
5505 PurpleAccount *account; 5440 PurpleAccount *account;
5506 char *gname, *gname_utf8, *alias, *alias_utf8; 5441 char *gname, *gname_utf8, *alias, *alias_utf8;
5507 PurpleBuddy *b; 5442 PurpleBuddy *b;
5508 PurpleGroup *g; 5443 PurpleGroup *g;
5509 struct aim_ssi_item *ssi_item; 5444 struct aim_ssi_item *ssi_item;
5510 aim_tlv_t *note_hash;
5511 va_list ap; 5445 va_list ap;
5512 guint16 snac_subtype, type; 5446 guint16 snac_subtype, type;
5513 const char *name; 5447 const char *name;
5514 5448
5515 gc = od->gc; 5449 gc = od->gc;
5573 5507
5574 } 5508 }
5575 5509
5576 ssi_item = aim_ssi_itemlist_finditem(od->ssi.local, 5510 ssi_item = aim_ssi_itemlist_finditem(od->ssi.local,
5577 gname, name, AIM_SSI_TYPE_BUDDY); 5511 gname, name, AIM_SSI_TYPE_BUDDY);
5578 if (ssi_item != NULL) 5512 if (ssi_item == NULL)
5579 {
5580 note_hash = aim_tlv_gettlv(ssi_item->data, 0x015c, 1);
5581 if (note_hash != NULL)
5582 aim_icq_getstatusnote(od, name, note_hash->value, note_hash->length);
5583 }
5584 else
5585 { 5513 {
5586 purple_debug_error("oscar", "purple_ssi_parseaddmod: " 5514 purple_debug_error("oscar", "purple_ssi_parseaddmod: "
5587 "Could not find ssi item for oncoming buddy %s, " 5515 "Could not find ssi item for oncoming buddy %s, "
5588 "group %s\n", name, gname); 5516 "group %s\n", name, gname);
5589 } 5517 }
6028 if (aim_ssi_waitingforauth(od->ssi.local, gname, name)) 5956 if (aim_ssi_waitingforauth(od->ssi.local, gname, name))
6029 ret = g_strdup(_("Not Authorized")); 5957 ret = g_strdup(_("Not Authorized"));
6030 else 5958 else
6031 ret = g_strdup(_("Offline")); 5959 ret = g_strdup(_("Offline"));
6032 } 5960 }
6033 else if (purple_status_is_available(status) && !strcmp(id, OSCAR_STATUS_ID_AVAILABLE)) 5961 else
6034 { 5962 {
6035 /* Available */
6036 message = purple_status_get_attr_string(status, "message");
6037 if (message != NULL)
6038 {
6039 ret = g_strdup(message);
6040 purple_util_chrreplace(ret, '\n', ' ');
6041 }
6042 }
6043 else if (!purple_status_is_available(status) && !strcmp(id, OSCAR_STATUS_ID_AWAY))
6044 {
6045 /* Away */
6046 message = purple_status_get_attr_string(status, "message"); 5963 message = purple_status_get_attr_string(status, "message");
6047 if (message != NULL) 5964 if (message != NULL)
6048 { 5965 {
6049 gchar *tmp1, *tmp2; 5966 gchar *tmp1, *tmp2;
6050 tmp1 = purple_markup_strip_html(message); 5967 tmp1 = purple_markup_strip_html(message);
6052 tmp2 = g_markup_escape_text(tmp1, -1); 5969 tmp2 = g_markup_escape_text(tmp1, -1);
6053 ret = purple_str_sub_away_formatters(tmp2, purple_account_get_username(account)); 5970 ret = purple_str_sub_away_formatters(tmp2, purple_account_get_username(account));
6054 g_free(tmp1); 5971 g_free(tmp1);
6055 g_free(tmp2); 5972 g_free(tmp2);
6056 } 5973 }
5974 else if (purple_status_is_available(status))
5975 {
5976 /* Don't show "Available" as status message in case buddy doesn't have a status message */
5977 }
6057 else 5978 else
6058 { 5979 {
6059 ret = g_strdup(_("Away")); 5980 ret = g_strdup(purple_status_get_name(status));
6060 } 5981 }
6061 } 5982 }
6062 else
6063 ret = g_strdup(purple_status_get_name(status));
6064 5983
6065 return ret; 5984 return ret;
6066 } 5985 }
6067 5986
6068 5987
6965 int i, j; 6884 int i, j;
6966 6885
6967 g_return_val_if_fail(str != NULL, NULL); 6886 g_return_val_if_fail(str != NULL, NULL);
6968 6887
6969 /* copy str to buf and skip all blanks */ 6888 /* copy str to buf and skip all blanks */
6970 for (i=0, j=0; str[j] && i < BUF_LEN - 1; i++, j++) 6889 i = 0;
6971 { 6890 for (j = 0; str[j]; j++) {
6972 while (str[j] == ' ') 6891 if (str[j] != ' ') {
6973 j++; 6892 buf[i++] = str[j];
6974 buf[i] = str[j]; 6893 if (i >= BUF_LEN - 1)
6894 break;
6895 }
6975 } 6896 }
6976 buf[i] = '\0'; 6897 buf[i] = '\0';
6977 6898
6978 tmp1 = g_utf8_strdown(buf, -1); 6899 tmp1 = g_utf8_strdown(buf, -1);
6979 tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT); 6900 tmp2 = g_utf8_normalize(tmp1, -1, G_NORMALIZE_DEFAULT);