Mon, 30 Jul 2007 22:36:20 +0000
Fix a stupid crash (that I introduced) that occurs when parsing gmail notifications. Fixes #2323
| 15225 | 1 | /** |
| 15884 | 2 | * Purple is the legal property of its developers, whose names are too numerous |
| 15225 | 3 | * to list here. Please refer to the COPYRIGHT file distributed with this |
| 4 | * source distribution. | |
| 5 | * | |
| 6 | * This program is free software; you can redistribute it and/or modify | |
| 7 | * it under the terms of the GNU General Public License as published by | |
| 8 | * the Free Software Foundation; either version 2 of the License, or | |
| 9 | * (at your option) any later version. | |
| 10 | * | |
| 11 | * This program is distributed in the hope that it will be useful, | |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | * GNU General Public License for more details. | |
| 15 | * | |
| 16 | * You should have received a copy of the GNU General Public License | |
| 17 | * along with this program; if not, write to the Free Software | |
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 | */ | |
| 20 | ||
| 21 | #include "internal.h" | |
| 22 | #include "debug.h" | |
|
15587
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
23 | #include "util.h" |
| 15265 | 24 | #include "privacy.h" |
| 25 | ||
| 26 | #include "buddy.h" | |
| 15225 | 27 | #include "google.h" |
| 28 | #include "jabber.h" | |
| 15265 | 29 | #include "presence.h" |
| 15225 | 30 | #include "iq.h" |
| 31 | ||
| 18233 | 32 | static void |
| 15225 | 33 | jabber_gmail_parse(JabberStream *js, xmlnode *packet, gpointer nul) |
| 34 | { | |
| 35 | const char *type = xmlnode_get_attrib(packet, "type"); | |
| 36 | xmlnode *child; | |
| 37 | xmlnode *message, *sender_node, *subject_node; | |
| 18739 | 38 | const char *from, *to, *url, *tid; |
| 39 | char *subject; | |
| 15225 | 40 | const char *in_str; |
| 41 | char *to_name; | |
| 42 | int i, count = 1, returned_count; | |
| 18233 | 43 | |
| 18739 | 44 | const char **tos, **froms, **urls; |
| 45 | char **subjects; | |
| 18233 | 46 | |
| 15225 | 47 | if (strcmp(type, "result")) |
| 48 | return; | |
| 18233 | 49 | |
| 15225 | 50 | child = xmlnode_get_child(packet, "mailbox"); |
| 51 | if (!child) | |
| 52 | return; | |
| 53 | ||
| 54 | in_str = xmlnode_get_attrib(child, "total-matched"); | |
| 18233 | 55 | if (in_str && *in_str) |
| 15225 | 56 | count = atoi(in_str); |
| 18233 | 57 | |
| 58 | if (count == 0) | |
| 15225 | 59 | return; |
| 60 | ||
| 61 | message = xmlnode_get_child(child, "mail-thread-info"); | |
| 18233 | 62 | |
| 15225 | 63 | /* Loop once to see how many messages were returned so we can allocate arrays |
| 64 | * accordingly */ | |
| 18233 | 65 | if (!message) |
| 15225 | 66 | return; |
| 67 | for (returned_count = 0; message; returned_count++, message=xmlnode_get_next_twin(message)); | |
| 18233 | 68 | |
| 15225 | 69 | froms = g_new0(const char* , returned_count); |
| 70 | tos = g_new0(const char* , returned_count); | |
| 18739 | 71 | subjects = g_new0(char* , returned_count); |
| 15225 | 72 | urls = g_new0(const char* , returned_count); |
| 18233 | 73 | |
| 15225 | 74 | to = xmlnode_get_attrib(packet, "to"); |
| 75 | to_name = jabber_get_bare_jid(to); | |
| 76 | url = xmlnode_get_attrib(child, "url"); | |
| 77 | if (!url || !*url) | |
| 78 | url = "http://www.gmail.com"; | |
| 18233 | 79 | |
| 15225 | 80 | message= xmlnode_get_child(child, "mail-thread-info"); |
| 81 | for (i=0; message; message = xmlnode_get_next_twin(message), i++) { | |
| 82 | subject_node = xmlnode_get_child(message, "subject"); | |
| 83 | sender_node = xmlnode_get_child(message, "senders"); | |
| 84 | sender_node = xmlnode_get_child(sender_node, "sender"); | |
| 85 | ||
| 18233 | 86 | while (sender_node && (!xmlnode_get_attrib(sender_node, "unread") || |
| 15225 | 87 | !strcmp(xmlnode_get_attrib(sender_node, "unread"),"0"))) |
| 88 | sender_node = xmlnode_get_next_twin(sender_node); | |
| 18233 | 89 | |
| 15225 | 90 | if (!sender_node) { |
| 91 | i--; | |
| 92 | continue; | |
| 93 | } | |
| 18233 | 94 | |
| 15225 | 95 | from = xmlnode_get_attrib(sender_node, "name"); |
| 96 | if (!from || !*from) | |
| 97 | from = xmlnode_get_attrib(sender_node, "address"); | |
| 98 | subject = xmlnode_get_data(subject_node); | |
| 99 | /* | |
| 100 | * url = xmlnode_get_attrib(message, "url"); | |
| 101 | */ | |
| 102 | tos[i] = (to_name != NULL ? to_name : ""); | |
| 103 | froms[i] = (from != NULL ? from : ""); | |
| 18739 | 104 | subjects[i] = (subject != NULL ? subject : g_strdup("")); |
| 15225 | 105 | urls[i] = (url != NULL ? url : ""); |
| 18233 | 106 | |
| 15225 | 107 | tid = xmlnode_get_attrib(message, "tid"); |
| 18233 | 108 | if (tid && |
| 15225 | 109 | (js->gmail_last_tid == NULL || strcmp(tid, js->gmail_last_tid) > 0)) { |
| 110 | g_free(js->gmail_last_tid); | |
| 111 | js->gmail_last_tid = g_strdup(tid); | |
| 112 | } | |
| 113 | } | |
| 114 | ||
| 18233 | 115 | if (i>0) |
|
18740
1b1f72624316
Only display the "detailed" email notifications for gtalk if we really have all the details to show. Fixes #1813.
Daniel Atallah <datallah@pidgin.im>
parents:
18739
diff
changeset
|
116 | purple_notify_emails(js->gc, count, count == i, (const char**) subjects, froms, tos, |
| 18233 | 117 | urls, NULL, NULL); |
| 15261 | 118 | |
| 15225 | 119 | g_free(to_name); |
| 120 | g_free(tos); | |
| 121 | g_free(froms); | |
|
19046
4c4a79e7e21c
Fix a stupid crash (that I introduced) that occurs when parsing gmail notifications. Fixes #2323
Daniel Atallah <datallah@pidgin.im>
parents:
18740
diff
changeset
|
122 | for (; i > 0; i--) |
|
4c4a79e7e21c
Fix a stupid crash (that I introduced) that occurs when parsing gmail notifications. Fixes #2323
Daniel Atallah <datallah@pidgin.im>
parents:
18740
diff
changeset
|
123 | g_free(subjects[i - 1]); |
| 15225 | 124 | g_free(subjects); |
| 125 | g_free(urls); | |
| 126 | ||
| 127 | in_str = xmlnode_get_attrib(child, "result-time"); | |
| 128 | if (in_str && *in_str) { | |
| 129 | g_free(js->gmail_last_time); | |
| 130 | js->gmail_last_time = g_strdup(in_str); | |
| 131 | } | |
| 132 | } | |
| 133 | ||
| 18233 | 134 | void |
| 135 | jabber_gmail_poke(JabberStream *js, xmlnode *packet) | |
| 15225 | 136 | { |
| 137 | const char *type; | |
| 138 | xmlnode *query; | |
| 139 | JabberIq *iq; | |
| 18233 | 140 | |
| 15225 | 141 | /* bail if the user isn't interested */ |
| 15884 | 142 | if (!purple_account_get_check_mail(js->gc->account)) |
| 15225 | 143 | return; |
| 144 | ||
| 145 | type = xmlnode_get_attrib(packet, "type"); | |
| 18233 | 146 | |
| 15225 | 147 | |
| 148 | /* Is this an initial incoming mail notification? If so, send a request for more info */ | |
| 149 | if (strcmp(type, "set") || !xmlnode_get_child(packet, "new-mail")) | |
| 150 | return; | |
| 151 | ||
| 15884 | 152 | purple_debug(PURPLE_DEBUG_MISC, "jabber", |
| 15225 | 153 | "Got new mail notification. Sending request for more info\n"); |
| 154 | ||
| 155 | iq = jabber_iq_new_query(js, JABBER_IQ_GET, "google:mail:notify"); | |
| 156 | jabber_iq_set_callback(iq, jabber_gmail_parse, NULL); | |
| 157 | query = xmlnode_get_child(iq->node, "query"); | |
| 158 | ||
| 159 | if (js->gmail_last_time) | |
| 160 | xmlnode_set_attrib(query, "newer-than-time", js->gmail_last_time); | |
| 161 | if (js->gmail_last_tid) | |
| 162 | xmlnode_set_attrib(query, "newer-than-tid", js->gmail_last_tid); | |
| 163 | ||
| 164 | jabber_iq_send(iq); | |
| 165 | return; | |
| 166 | } | |
| 167 | ||
| 168 | void jabber_gmail_init(JabberStream *js) { | |
| 169 | JabberIq *iq; | |
| 170 | ||
| 18233 | 171 | if (!purple_account_get_check_mail(js->gc->account)) |
| 15225 | 172 | return; |
| 173 | ||
| 174 | iq = jabber_iq_new_query(js, JABBER_IQ_GET, "google:mail:notify"); | |
| 175 | jabber_iq_set_callback(iq, jabber_gmail_parse, NULL); | |
| 176 | jabber_iq_send(iq); | |
| 177 | } | |
| 15265 | 178 | |
| 179 | void jabber_google_roster_init(JabberStream *js) | |
| 180 | { | |
| 181 | JabberIq *iq; | |
| 182 | xmlnode *query; | |
| 183 | ||
| 184 | iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:roster"); | |
| 185 | query = xmlnode_get_child(iq->node, "query"); | |
| 18233 | 186 | |
| 15265 | 187 | xmlnode_set_attrib(query, "xmlns:gr", "google:roster"); |
| 188 | xmlnode_set_attrib(query, "gr:ext", "2"); | |
| 189 | ||
| 190 | jabber_iq_send(iq); | |
| 191 | } | |
| 192 | ||
| 193 | void jabber_google_roster_outgoing(JabberStream *js, xmlnode *query, xmlnode *item) | |
| 194 | { | |
| 15884 | 195 | PurpleAccount *account = purple_connection_get_account(js->gc); |
| 15265 | 196 | GSList *list = account->deny; |
| 197 | const char *jid = xmlnode_get_attrib(item, "jid"); | |
| 198 | char *jid_norm = g_strdup(jabber_normalize(account, jid)); | |
| 199 | ||
| 200 | while (list) { | |
| 201 | if (!strcmp(jid_norm, (char*)list->data)) { | |
| 202 | xmlnode_set_attrib(query, "xmlns:gr", "google:roster"); | |
| 203 | xmlnode_set_attrib(item, "gr:t", "B"); | |
| 204 | xmlnode_set_attrib(query, "xmlns:gr", "google:roster"); | |
| 205 | xmlnode_set_attrib(query, "gr:ext", "2"); | |
| 206 | return; | |
| 207 | } | |
| 208 | list = list->next; | |
| 209 | } | |
| 210 | ||
| 18739 | 211 | g_free(jid_norm); |
| 212 | ||
| 15265 | 213 | } |
| 214 | ||
|
15530
9355a1be068e
Make deleting Google Talk buddies work
Sean Egan <seanegan@pidgin.im>
parents:
15435
diff
changeset
|
215 | gboolean jabber_google_roster_incoming(JabberStream *js, xmlnode *item) |
| 15265 | 216 | { |
| 15884 | 217 | PurpleAccount *account = purple_connection_get_account(js->gc); |
| 15265 | 218 | GSList *list = account->deny; |
| 219 | const char *jid = xmlnode_get_attrib(item, "jid"); | |
| 220 | gboolean on_block_list = FALSE; | |
| 221 | ||
| 222 | char *jid_norm = g_strdup(jabber_normalize(account, jid)); | |
| 223 | ||
| 224 | const char *grt = xmlnode_get_attrib_with_namespace(item, "t", "google:roster"); | |
|
17148
db0801f13aa8
If Google Talk tells you a roster item as a none subscription, we probably don't ever want to show it. Fixes #1189
Sean Egan <seanegan@pidgin.im>
parents:
16988
diff
changeset
|
225 | const char *subscription = xmlnode_get_attrib(item, "subscription"); |
| 18233 | 226 | |
| 17327 | 227 | if (!subscription || !strcmp(subscription, "none")) { |
|
17148
db0801f13aa8
If Google Talk tells you a roster item as a none subscription, we probably don't ever want to show it. Fixes #1189
Sean Egan <seanegan@pidgin.im>
parents:
16988
diff
changeset
|
228 | /* The Google Talk servers will automatically add people from your Gmail address book |
|
db0801f13aa8
If Google Talk tells you a roster item as a none subscription, we probably don't ever want to show it. Fixes #1189
Sean Egan <seanegan@pidgin.im>
parents:
16988
diff
changeset
|
229 | * with subscription=none. If we see someone with subscription=none, ignore them. |
|
db0801f13aa8
If Google Talk tells you a roster item as a none subscription, we probably don't ever want to show it. Fixes #1189
Sean Egan <seanegan@pidgin.im>
parents:
16988
diff
changeset
|
230 | */ |
|
db0801f13aa8
If Google Talk tells you a roster item as a none subscription, we probably don't ever want to show it. Fixes #1189
Sean Egan <seanegan@pidgin.im>
parents:
16988
diff
changeset
|
231 | return FALSE; |
|
db0801f13aa8
If Google Talk tells you a roster item as a none subscription, we probably don't ever want to show it. Fixes #1189
Sean Egan <seanegan@pidgin.im>
parents:
16988
diff
changeset
|
232 | } |
| 18233 | 233 | |
| 15265 | 234 | while (list) { |
| 235 | if (!strcmp(jid_norm, (char*)list->data)) { | |
| 236 | on_block_list = TRUE; | |
| 237 | break; | |
| 238 | } | |
| 239 | list = list->next; | |
| 240 | } | |
| 18233 | 241 | |
|
15530
9355a1be068e
Make deleting Google Talk buddies work
Sean Egan <seanegan@pidgin.im>
parents:
15435
diff
changeset
|
242 | if (grt && (*grt == 'H' || *grt == 'h')) { |
| 15884 | 243 | PurpleBuddy *buddy = purple_find_buddy(account, jid_norm); |
| 244 | purple_blist_remove_buddy(buddy); | |
| 18739 | 245 | g_free(jid_norm); |
|
15530
9355a1be068e
Make deleting Google Talk buddies work
Sean Egan <seanegan@pidgin.im>
parents:
15435
diff
changeset
|
246 | return FALSE; |
|
9355a1be068e
Make deleting Google Talk buddies work
Sean Egan <seanegan@pidgin.im>
parents:
15435
diff
changeset
|
247 | } |
| 18233 | 248 | |
| 15265 | 249 | if (!on_block_list && (grt && (*grt == 'B' || *grt == 'b'))) { |
| 15884 | 250 | purple_debug_info("jabber", "Blocking %s\n", jid_norm); |
| 251 | purple_privacy_deny_add(account, jid_norm, TRUE); | |
| 15265 | 252 | } else if (on_block_list && (!grt || (*grt != 'B' && *grt != 'b' ))){ |
| 15884 | 253 | purple_debug_info("jabber", "Unblocking %s\n", jid_norm); |
| 254 | purple_privacy_deny_remove(account, jid_norm, TRUE); | |
| 15265 | 255 | } |
| 18739 | 256 | |
| 257 | g_free(jid_norm); | |
|
15530
9355a1be068e
Make deleting Google Talk buddies work
Sean Egan <seanegan@pidgin.im>
parents:
15435
diff
changeset
|
258 | return TRUE; |
| 15265 | 259 | } |
| 260 | ||
| 18233 | 261 | void jabber_google_roster_add_deny(PurpleConnection *gc, const char *who) |
| 15265 | 262 | { |
| 263 | JabberStream *js; | |
| 264 | GSList *buddies; | |
| 265 | JabberIq *iq; | |
| 266 | xmlnode *query; | |
| 267 | xmlnode *item; | |
| 268 | xmlnode *group; | |
| 15884 | 269 | PurpleBuddy *b; |
| 15265 | 270 | JabberBuddy *jb; |
| 271 | ||
| 272 | js = (JabberStream*)(gc->proto_data); | |
| 18233 | 273 | |
| 15265 | 274 | if (!js || !js->server_caps & JABBER_CAP_GOOGLE_ROSTER) |
| 275 | return; | |
| 276 | ||
| 277 | jb = jabber_buddy_find(js, who, TRUE); | |
| 278 | ||
| 15884 | 279 | buddies = purple_find_buddies(js->gc->account, who); |
| 15265 | 280 | if(!buddies) |
| 281 | return; | |
| 18233 | 282 | |
| 15265 | 283 | b = buddies->data; |
| 284 | ||
| 285 | iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster"); | |
| 18233 | 286 | |
| 15265 | 287 | query = xmlnode_get_child(iq->node, "query"); |
| 288 | item = xmlnode_new_child(query, "item"); | |
| 289 | ||
| 290 | while(buddies) { | |
| 15884 | 291 | PurpleGroup *g; |
| 15265 | 292 | |
| 293 | b = buddies->data; | |
| 15884 | 294 | g = purple_buddy_get_group(b); |
| 15265 | 295 | |
| 296 | group = xmlnode_new_child(item, "group"); | |
| 297 | xmlnode_insert_data(group, g->name, -1); | |
| 18233 | 298 | |
| 15265 | 299 | buddies = buddies->next; |
| 300 | } | |
| 301 | ||
| 302 | iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster"); | |
| 303 | ||
| 304 | query = xmlnode_get_child(iq->node, "query"); | |
| 305 | item = xmlnode_new_child(query, "item"); | |
| 306 | ||
| 307 | xmlnode_set_attrib(item, "jid", who); | |
| 308 | xmlnode_set_attrib(item, "name", b->alias ? b->alias : ""); | |
| 309 | xmlnode_set_attrib(item, "gr:t", "B"); | |
| 310 | xmlnode_set_attrib(query, "xmlns:gr", "google:roster"); | |
| 311 | xmlnode_set_attrib(query, "gr:ext", "2"); | |
| 312 | ||
| 313 | jabber_iq_send(iq); | |
| 314 | ||
| 315 | /* Synthesize a sign-off */ | |
| 316 | if (jb) { | |
| 317 | JabberBuddyResource *jbr; | |
| 318 | GList *l = jb->resources; | |
| 319 | while (l) { | |
| 320 | jbr = l->data; | |
|
15346
ef48613b5b9b
[gaim-migrate @ 18074]
Evan Schoenberg <evands@pidgin.im>
parents:
15265
diff
changeset
|
321 | if (jbr && jbr->name) |
|
ef48613b5b9b
[gaim-migrate @ 18074]
Evan Schoenberg <evands@pidgin.im>
parents:
15265
diff
changeset
|
322 | { |
| 15884 | 323 | purple_debug(PURPLE_DEBUG_MISC, "jabber", "Removing resource %s\n", jbr->name); |
|
15346
ef48613b5b9b
[gaim-migrate @ 18074]
Evan Schoenberg <evands@pidgin.im>
parents:
15265
diff
changeset
|
324 | jabber_buddy_remove_resource(jb, jbr->name); |
|
ef48613b5b9b
[gaim-migrate @ 18074]
Evan Schoenberg <evands@pidgin.im>
parents:
15265
diff
changeset
|
325 | } |
| 15265 | 326 | l = l->next; |
| 327 | } | |
| 328 | } | |
| 15884 | 329 | purple_prpl_got_user_status(purple_connection_get_account(gc), who, "offline", NULL); |
| 15265 | 330 | } |
| 331 | ||
| 15884 | 332 | void jabber_google_roster_rem_deny(PurpleConnection *gc, const char *who) |
| 15265 | 333 | { |
| 334 | JabberStream *js; | |
| 335 | GSList *buddies; | |
| 336 | JabberIq *iq; | |
| 337 | xmlnode *query; | |
| 338 | xmlnode *item; | |
| 339 | xmlnode *group; | |
| 15884 | 340 | PurpleBuddy *b; |
| 15265 | 341 | |
| 342 | g_return_if_fail(gc != NULL); | |
| 343 | g_return_if_fail(who != NULL); | |
| 18233 | 344 | |
| 15265 | 345 | js = (JabberStream*)(gc->proto_data); |
| 18233 | 346 | |
| 15265 | 347 | if (!js || !js->server_caps & JABBER_CAP_GOOGLE_ROSTER) |
| 348 | return; | |
| 18233 | 349 | |
| 15884 | 350 | buddies = purple_find_buddies(js->gc->account, who); |
| 15265 | 351 | if(!buddies) |
| 352 | return; | |
| 18233 | 353 | |
| 15265 | 354 | b = buddies->data; |
| 355 | ||
| 356 | iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster"); | |
| 18233 | 357 | |
| 15265 | 358 | query = xmlnode_get_child(iq->node, "query"); |
| 359 | item = xmlnode_new_child(query, "item"); | |
| 360 | ||
| 361 | while(buddies) { | |
| 15884 | 362 | PurpleGroup *g; |
| 15265 | 363 | |
| 364 | b = buddies->data; | |
| 15884 | 365 | g = purple_buddy_get_group(b); |
| 15265 | 366 | |
| 367 | group = xmlnode_new_child(item, "group"); | |
| 368 | xmlnode_insert_data(group, g->name, -1); | |
| 18233 | 369 | |
| 15265 | 370 | buddies = buddies->next; |
| 371 | } | |
| 372 | ||
| 373 | iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:roster"); | |
| 374 | ||
| 375 | query = xmlnode_get_child(iq->node, "query"); | |
| 376 | item = xmlnode_new_child(query, "item"); | |
| 377 | ||
| 378 | xmlnode_set_attrib(item, "jid", who); | |
| 379 | xmlnode_set_attrib(item, "name", b->alias ? b->alias : ""); | |
| 380 | xmlnode_set_attrib(query, "xmlns:gr", "google:roster"); | |
| 381 | xmlnode_set_attrib(query, "gr:ext", "2"); | |
| 382 | ||
| 383 | jabber_iq_send(iq); | |
| 384 | ||
| 385 | /* See if he's online */ | |
| 386 | jabber_presence_subscription_set(js, who, "probe"); | |
| 387 | } | |
|
15587
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
388 | |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
389 | /* This does two passes on the string. The first pass goes through |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
390 | * and determine if all the structured text is properly balanced, and |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
391 | * how many instances of each there is. The second pass goes and converts |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
392 | * everything to HTML, depending on what's figured out by the first pass. |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
393 | * It will short circuit once it knows it has no more replacements to make |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
394 | */ |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
395 | char *jabber_google_format_to_html(const char *text) |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
396 | { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
397 | const char *p; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
398 | |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
399 | /* The start of the screen may be consdiered a space for this purpose */ |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
400 | gboolean preceding_space = TRUE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
401 | |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
402 | gboolean in_bold = FALSE, in_italic = FALSE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
403 | gboolean in_tag = FALSE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
404 | |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
405 | gint bold_count = 0, italic_count = 0; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
406 | |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
407 | GString *str; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
408 | |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
409 | for (p = text; *p != '\0'; p = g_utf8_next_char(p)) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
410 | gunichar c = g_utf8_get_char(p); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
411 | if (c == '*' && !in_tag) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
412 | if (in_bold && (g_unichar_isspace(*(p+1)) || |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
413 | *(p+1) == '\0' || |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
414 | *(p+1) == '<')) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
415 | bold_count++; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
416 | in_bold = FALSE; |
|
16988
1aaf51bf0f23
Patch #265. Fix to Google Talk formatting
Sean Egan <seanegan@pidgin.im>
parents:
15884
diff
changeset
|
417 | } else if (preceding_space && !in_bold && !g_unichar_isspace(*(p+1))) { |
|
15587
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
418 | bold_count++; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
419 | in_bold = TRUE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
420 | } |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
421 | preceding_space = TRUE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
422 | } else if (c == '_' && !in_tag) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
423 | if (in_italic && (g_unichar_isspace(*(p+1)) || |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
424 | *(p+1) == '\0' || |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
425 | *(p+1) == '<')) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
426 | italic_count++; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
427 | in_italic = FALSE; |
|
16988
1aaf51bf0f23
Patch #265. Fix to Google Talk formatting
Sean Egan <seanegan@pidgin.im>
parents:
15884
diff
changeset
|
428 | } else if (preceding_space && !in_italic && !g_unichar_isspace(*(p+1))) { |
|
15587
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
429 | italic_count++; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
430 | in_italic = TRUE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
431 | } |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
432 | preceding_space = TRUE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
433 | } else if (c == '<' && !in_tag) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
434 | in_tag = TRUE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
435 | } else if (c == '>' && in_tag) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
436 | in_tag = FALSE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
437 | } else if (!in_tag) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
438 | if (g_unichar_isspace(c)) |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
439 | preceding_space = TRUE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
440 | else |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
441 | preceding_space = FALSE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
442 | } |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
443 | } |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
444 | |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
445 | str = g_string_new(NULL); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
446 | in_bold = in_italic = in_tag = FALSE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
447 | preceding_space = TRUE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
448 | |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
449 | for (p = text; *p != '\0'; p = g_utf8_next_char(p)) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
450 | gunichar c = g_utf8_get_char(p); |
| 18233 | 451 | |
|
15587
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
452 | if (bold_count < 2 && italic_count < 2 && !in_bold && !in_italic) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
453 | g_string_append(str, p); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
454 | return g_string_free(str, FALSE); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
455 | } |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
456 | |
| 18233 | 457 | |
|
15587
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
458 | if (c == '*' && !in_tag) { |
| 18233 | 459 | if (in_bold && |
|
15587
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
460 | (g_unichar_isspace(*(p+1))||*(p+1)=='<')) { /* This is safe in UTF-8 */ |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
461 | str = g_string_append(str, "</b>"); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
462 | in_bold = FALSE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
463 | bold_count--; |
|
16988
1aaf51bf0f23
Patch #265. Fix to Google Talk formatting
Sean Egan <seanegan@pidgin.im>
parents:
15884
diff
changeset
|
464 | } else if (preceding_space && bold_count > 1 && !g_unichar_isspace(*(p+1))) { |
|
15587
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
465 | str = g_string_append(str, "<b>"); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
466 | bold_count--; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
467 | in_bold = TRUE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
468 | } else { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
469 | str = g_string_append_unichar(str, c); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
470 | } |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
471 | preceding_space = TRUE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
472 | } else if (c == '_' && !in_tag) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
473 | if (in_italic && |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
474 | (g_unichar_isspace(*(p+1))||*(p+1)=='<')) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
475 | str = g_string_append(str, "</i>"); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
476 | italic_count--; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
477 | in_italic = FALSE; |
|
16988
1aaf51bf0f23
Patch #265. Fix to Google Talk formatting
Sean Egan <seanegan@pidgin.im>
parents:
15884
diff
changeset
|
478 | } else if (preceding_space && italic_count > 1 && !g_unichar_isspace(*(p+1))) { |
|
15587
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
479 | str = g_string_append(str, "<i>"); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
480 | italic_count--; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
481 | in_italic = TRUE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
482 | } else { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
483 | str = g_string_append_unichar(str, c); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
484 | } |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
485 | preceding_space = TRUE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
486 | } else if (c == '<' && !in_tag) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
487 | str = g_string_append_unichar(str, c); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
488 | in_tag = TRUE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
489 | } else if (c == '>' && in_tag) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
490 | str = g_string_append_unichar(str, c); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
491 | in_tag = FALSE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
492 | } else if (!in_tag) { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
493 | str = g_string_append_unichar(str, c); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
494 | if (g_unichar_isspace(c)) |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
495 | preceding_space = TRUE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
496 | else |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
497 | preceding_space = FALSE; |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
498 | } else { |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
499 | str = g_string_append_unichar(str, c); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
500 | } |
| 18233 | 501 | } |
|
15587
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
502 | return g_string_free(str, FALSE); |
|
cbedd543bfae
Google Talk uses structured text formatting where *this* is bold
Sean Egan <seanegan@pidgin.im>
parents:
15530
diff
changeset
|
503 | } |