Mercurial > pidgin
annotate libgaim/server.c @ 15113:4a8c368df4ea
[gaim-migrate @ 17899]
Some touchups:
* If one of the parallel connection attempts fails immediately (i.e.
does not time out) then don't cancel the other one.
* Make sure we don't continue on to step 2 of the peer connection
process after we kick off the parallel gaim_proxy_connects(). It
looks like this would happen most of the time, because the
connect_timeout_timer would be added for the verified ip, so it
would NOT be added for the client ip, and so we wouldn't hit the
"return" call because it happens to be in the same block as the
second gaim_timeout_add() call.
* Add the connection timeout timer even if the gaim_proxy_connect() to
the verified ip returns NULL for some crazy reason.
I didn't actually test any of this. I should probably do that when
I get home.
committer: Tailor Script <tailor@pidgin.im>
| author | Mark Doliner <mark@kingant.net> |
|---|---|
| date | Wed, 06 Dec 2006 01:29:59 +0000 |
| parents | 0a9c44ce9a4a |
| children | a6aad36ca735 |
| rev | line source |
|---|---|
| 14192 | 1 /* |
| 2 * gaim | |
| 3 * | |
| 4 * Gaim is the legal property of its developers, whose names are too numerous | |
| 5 * to list here. Please refer to the COPYRIGHT file distributed with this | |
| 6 * source distribution. | |
| 7 * | |
| 8 * This program is free software; you can redistribute it and/or modify | |
| 9 * it under the terms of the GNU General Public License as published by | |
| 10 * the Free Software Foundation; either version 2 of the License, or | |
| 11 * (at your option) any later version. | |
| 12 * | |
| 13 * This program is distributed in the hope that it will be useful, | |
| 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 16 * GNU General Public License for more details. | |
| 17 * | |
| 18 * You should have received a copy of the GNU General Public License | |
| 19 * along with this program; if not, write to the Free Software | |
| 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 21 * | |
| 22 */ | |
| 23 #include "internal.h" | |
| 24 #include "blist.h" | |
| 25 #include "conversation.h" | |
| 26 #include "debug.h" | |
| 27 #include "log.h" | |
| 28 #include "notify.h" | |
| 29 #include "prefs.h" | |
| 30 #include "privacy.h" | |
| 31 #include "prpl.h" | |
| 32 #include "request.h" | |
| 33 #include "signals.h" | |
| 34 #include "server.h" | |
| 35 #include "status.h" | |
| 36 #include "util.h" | |
| 37 | |
| 38 #define SECS_BEFORE_RESENDING_AUTORESPONSE 600 | |
| 39 #define SEX_BEFORE_RESENDING_AUTORESPONSE "Only after you're married" | |
| 40 | |
| 41 unsigned int | |
| 42 serv_send_typing(GaimConnection *gc, const char *name, GaimTypingState state) | |
| 43 { | |
| 44 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 45 | |
| 46 if (gc != NULL && gc->prpl != NULL) | |
| 47 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
| 48 | |
| 49 if (prpl_info && prpl_info->send_typing) | |
| 50 return prpl_info->send_typing(gc, name, state); | |
| 51 | |
| 52 return 0; | |
| 53 } | |
| 54 | |
| 55 static GSList *last_auto_responses = NULL; | |
| 56 struct last_auto_response { | |
| 57 GaimConnection *gc; | |
| 58 char name[80]; | |
| 59 time_t sent; | |
| 60 }; | |
| 61 | |
| 62 static gboolean | |
| 63 expire_last_auto_responses(gpointer data) | |
| 64 { | |
| 65 GSList *tmp, *cur; | |
| 66 struct last_auto_response *lar; | |
| 67 | |
| 68 tmp = last_auto_responses; | |
| 69 | |
| 70 while (tmp) { | |
| 71 cur = tmp; | |
| 72 tmp = tmp->next; | |
| 73 lar = (struct last_auto_response *)cur->data; | |
| 74 | |
| 75 if ((time(NULL) - lar->sent) > SECS_BEFORE_RESENDING_AUTORESPONSE) { | |
| 76 last_auto_responses = g_slist_remove(last_auto_responses, lar); | |
| 77 g_free(lar); | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 return FALSE; /* do not run again */ | |
| 82 } | |
| 83 | |
| 84 static struct last_auto_response * | |
| 85 get_last_auto_response(GaimConnection *gc, const char *name) | |
| 86 { | |
| 87 GSList *tmp; | |
| 88 struct last_auto_response *lar; | |
| 89 | |
| 90 /* because we're modifying or creating a lar, schedule the | |
| 91 * function to expire them as the pref dictates */ | |
| 92 gaim_timeout_add((SECS_BEFORE_RESENDING_AUTORESPONSE + 1) * 1000, expire_last_auto_responses, NULL); | |
| 93 | |
| 94 tmp = last_auto_responses; | |
| 95 | |
| 96 while (tmp) { | |
| 97 lar = (struct last_auto_response *)tmp->data; | |
| 98 | |
| 99 if (gc == lar->gc && !strncmp(name, lar->name, sizeof(lar->name))) | |
| 100 return lar; | |
| 101 | |
| 102 tmp = tmp->next; | |
| 103 } | |
| 104 | |
| 105 lar = (struct last_auto_response *)g_new0(struct last_auto_response, 1); | |
| 106 g_snprintf(lar->name, sizeof(lar->name), "%s", name); | |
| 107 lar->gc = gc; | |
| 108 lar->sent = 0; | |
| 109 last_auto_responses = g_slist_prepend(last_auto_responses, lar); | |
| 110 | |
| 111 return lar; | |
| 112 } | |
| 113 | |
| 114 int serv_send_im(GaimConnection *gc, const char *name, const char *message, | |
| 115 GaimMessageFlags flags) | |
| 116 { | |
| 117 GaimConversation *conv; | |
| 118 GaimAccount *account; | |
| 119 GaimPresence *presence; | |
| 120 GaimPluginProtocolInfo *prpl_info; | |
| 121 int val = -EINVAL; | |
| 122 const gchar *auto_reply_pref; | |
| 123 | |
| 124 g_return_val_if_fail(gc != NULL, val); | |
| 125 g_return_val_if_fail(gc->prpl != NULL, val); | |
| 126 | |
| 127 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
| 128 | |
| 129 account = gaim_connection_get_account(gc); | |
| 130 presence = gaim_account_get_presence(account); | |
| 131 | |
| 132 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, gc->account); | |
| 133 | |
| 134 if (prpl_info && prpl_info->send_im) | |
| 135 val = prpl_info->send_im(gc, name, message, flags); | |
| 136 | |
| 137 /* | |
| 138 * XXX - If "only auto-reply when away & idle" is set, then shouldn't | |
| 139 * this only reset lar->sent if we're away AND idle? | |
| 140 */ | |
| 141 auto_reply_pref = gaim_prefs_get_string("/core/away/auto_reply"); | |
| 142 if ((gc->flags & GAIM_CONNECTION_AUTO_RESP) && | |
| 143 !gaim_presence_is_available(presence) && | |
| 144 strcmp(auto_reply_pref, "never")) { | |
| 145 | |
| 146 struct last_auto_response *lar; | |
| 147 lar = get_last_auto_response(gc, name); | |
| 148 lar->sent = time(NULL); | |
| 149 } | |
| 150 | |
| 151 if (conv && gaim_conv_im_get_send_typed_timeout(GAIM_CONV_IM(conv))) | |
| 152 gaim_conv_im_stop_send_typed_timeout(GAIM_CONV_IM(conv)); | |
| 153 | |
| 154 return val; | |
| 155 } | |
| 156 | |
| 157 void serv_get_info(GaimConnection *gc, const char *name) | |
| 158 { | |
| 159 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 160 | |
| 161 if (gc != NULL && gc->prpl != NULL) | |
| 162 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
| 163 | |
| 164 if (gc && prpl_info && prpl_info->get_info) | |
| 165 prpl_info->get_info(gc, name); | |
| 166 } | |
| 167 | |
| 168 void serv_set_info(GaimConnection *gc, const char *info) | |
| 169 { | |
| 170 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 171 GaimAccount *account; | |
| 172 | |
| 173 if (gc != NULL && gc->prpl != NULL) | |
| 174 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
| 175 | |
| 14607 | 176 if (prpl_info && prpl_info->set_info) { |
| 14192 | 177 |
| 178 account = gaim_connection_get_account(gc); | |
| 179 | |
| 180 if (gaim_signal_emit_return_1(gaim_accounts_get_handle(), | |
| 181 "account-setting-info", account, info)) | |
| 182 return; | |
| 183 | |
| 184 prpl_info->set_info(gc, info); | |
| 185 | |
| 186 gaim_signal_emit(gaim_accounts_get_handle(), | |
| 187 "account-set-info", account, info); | |
| 188 } | |
| 189 } | |
| 190 | |
| 191 /* | |
| 192 * Set buddy's alias on server roster/list | |
| 193 */ | |
| 194 void serv_alias_buddy(GaimBuddy *b) | |
| 195 { | |
| 196 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 197 | |
| 198 if (b != NULL && b->account->gc->prpl != NULL) | |
| 199 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(b->account->gc->prpl); | |
| 200 | |
| 201 if (b && prpl_info && prpl_info->alias_buddy) { | |
| 202 prpl_info->alias_buddy(b->account->gc, b->name, b->alias); | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 void | |
| 207 serv_got_alias(GaimConnection *gc, const char *who, const char *alias) | |
| 208 { | |
| 209 GaimAccount *account = gaim_connection_get_account(gc); | |
| 210 GSList *buds, *buddies = gaim_find_buddies(account, who); | |
| 211 GaimBuddy *b; | |
| 212 GaimConversation *conv; | |
| 213 | |
| 214 for (buds = buddies; buds; buds = buds->next) | |
| 215 { | |
| 216 b = buds->data; | |
|
14496
aee74d84816c
[gaim-migrate @ 17215]
Richard Laager <rlaager@wiktel.com>
parents:
14484
diff
changeset
|
217 if ((b->server_alias == NULL && alias == NULL) || |
|
aee74d84816c
[gaim-migrate @ 17215]
Richard Laager <rlaager@wiktel.com>
parents:
14484
diff
changeset
|
218 (b->server_alias && alias && !strcmp(b->server_alias, alias))) |
|
aee74d84816c
[gaim-migrate @ 17215]
Richard Laager <rlaager@wiktel.com>
parents:
14484
diff
changeset
|
219 { |
|
14484
1f81919515ae
[gaim-migrate @ 17203]
Richard Laager <rlaager@wiktel.com>
parents:
14192
diff
changeset
|
220 continue; |
|
14496
aee74d84816c
[gaim-migrate @ 17215]
Richard Laager <rlaager@wiktel.com>
parents:
14484
diff
changeset
|
221 } |
| 14192 | 222 gaim_blist_server_alias_buddy(b, alias); |
| 223 | |
| 224 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, b->name, account); | |
| 225 | |
|
14496
aee74d84816c
[gaim-migrate @ 17215]
Richard Laager <rlaager@wiktel.com>
parents:
14484
diff
changeset
|
226 if (conv != NULL && alias != NULL) |
| 14192 | 227 { |
| 228 char *tmp = g_strdup_printf(_("%s is now known as %s.\n"), | |
| 229 who, alias); | |
| 230 | |
| 231 gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, | |
| 232 time(NULL)); | |
| 233 | |
| 234 g_free(tmp); | |
| 235 } | |
| 236 } | |
| 237 g_slist_free(buddies); | |
| 238 } | |
| 239 | |
| 240 /* | |
| 241 * Move a buddy from one group to another on server. | |
| 242 * | |
| 243 * Note: For now we'll not deal with changing gc's at the same time, but | |
| 244 * it should be possible. Probably needs to be done, someday. Although, | |
| 245 * the UI for that would be difficult, because groups are Gaim-wide. | |
| 246 */ | |
| 247 void serv_move_buddy(GaimBuddy *b, GaimGroup *og, GaimGroup *ng) | |
| 248 { | |
| 249 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 250 | |
| 251 g_return_if_fail(b != NULL); | |
| 252 g_return_if_fail(og != NULL); | |
| 253 g_return_if_fail(ng != NULL); | |
| 254 | |
| 255 if (b->account->gc != NULL && b->account->gc->prpl != NULL) | |
| 256 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(b->account->gc->prpl); | |
| 257 | |
| 258 if (b->account->gc && og && ng) { | |
| 259 if (prpl_info && prpl_info->group_buddy) { | |
| 260 prpl_info->group_buddy(b->account->gc, b->name, og->name, ng->name); | |
| 261 } | |
| 262 } | |
| 263 } | |
| 264 | |
| 265 void serv_add_permit(GaimConnection *g, const char *name) | |
| 266 { | |
| 267 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 268 | |
| 269 if (g != NULL && g->prpl != NULL) | |
| 270 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
| 271 | |
| 14607 | 272 if (prpl_info && prpl_info->add_permit) |
| 14192 | 273 prpl_info->add_permit(g, name); |
| 274 } | |
| 275 | |
| 276 void serv_add_deny(GaimConnection *g, const char *name) | |
| 277 { | |
| 278 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 279 | |
| 280 if (g != NULL && g->prpl != NULL) | |
| 281 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
| 282 | |
| 14607 | 283 if (prpl_info && prpl_info->add_deny) |
| 14192 | 284 prpl_info->add_deny(g, name); |
| 285 } | |
| 286 | |
| 287 void serv_rem_permit(GaimConnection *g, const char *name) | |
| 288 { | |
| 289 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 290 | |
| 291 if (g != NULL && g->prpl != NULL) | |
| 292 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
| 293 | |
| 14607 | 294 if (prpl_info && prpl_info->rem_permit) |
| 14192 | 295 prpl_info->rem_permit(g, name); |
| 296 } | |
| 297 | |
| 298 void serv_rem_deny(GaimConnection *g, const char *name) | |
| 299 { | |
| 300 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 301 | |
| 302 if (g != NULL && g->prpl != NULL) | |
| 303 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
| 304 | |
| 14607 | 305 if (prpl_info && prpl_info->rem_deny) |
| 14192 | 306 prpl_info->rem_deny(g, name); |
| 307 } | |
| 308 | |
| 309 void serv_set_permit_deny(GaimConnection *g) | |
| 310 { | |
| 311 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 312 | |
| 313 if (g != NULL && g->prpl != NULL) | |
| 314 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
| 315 | |
| 316 /* | |
| 317 * this is called when either you import a buddy list, and make lots | |
| 318 * of changes that way, or when the user toggles the permit/deny mode | |
| 319 * in the prefs. In either case you should probably be resetting and | |
| 320 * resending the permit/deny info when you get this. | |
| 321 */ | |
| 14607 | 322 if (prpl_info && prpl_info->set_permit_deny) |
| 14192 | 323 prpl_info->set_permit_deny(g); |
| 324 } | |
| 325 | |
| 326 void serv_join_chat(GaimConnection *g, GHashTable *data) | |
| 327 { | |
| 328 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 329 | |
| 330 if (g != NULL && g->prpl != NULL) | |
| 331 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
| 332 | |
| 14607 | 333 if (prpl_info && prpl_info->join_chat) |
| 14192 | 334 prpl_info->join_chat(g, data); |
| 335 } | |
| 336 | |
| 337 | |
| 338 void serv_reject_chat(GaimConnection *g, GHashTable *data) | |
| 339 { | |
| 340 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 341 | |
| 342 if (g != NULL && g->prpl != NULL) | |
| 343 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
| 344 | |
| 14607 | 345 if (prpl_info && prpl_info->reject_chat) |
| 14192 | 346 prpl_info->reject_chat(g, data); |
| 347 } | |
| 348 | |
| 349 void serv_chat_invite(GaimConnection *g, int id, const char *message, const char *name) | |
| 350 { | |
| 351 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 352 GaimConversation *conv; | |
| 353 char *buffy = message && *message ? g_strdup(message) : NULL; | |
| 354 | |
| 355 conv = gaim_find_chat(g, id); | |
| 356 | |
| 357 if (conv == NULL) | |
| 358 return; | |
| 359 | |
| 360 if (g != NULL && g->prpl != NULL) | |
| 361 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
| 362 | |
| 363 gaim_signal_emit(gaim_conversations_get_handle(), "chat-inviting-user", | |
| 364 conv, name, &buffy); | |
| 365 | |
| 14607 | 366 if (prpl_info && prpl_info->chat_invite) |
| 14192 | 367 prpl_info->chat_invite(g, id, buffy, name); |
| 368 | |
| 369 gaim_signal_emit(gaim_conversations_get_handle(), "chat-invited-user", | |
| 370 conv, name, buffy); | |
| 371 | |
| 372 g_free(buffy); | |
| 373 } | |
| 374 | |
| 375 /* Ya know, nothing uses this except gaim_conversation_destroy(), | |
| 376 * I think I'll just merge it into that later... | |
| 377 * Then again, something might want to use this, from outside prpl-land | |
| 378 * to leave a chat without destroying the conversation. | |
| 379 */ | |
| 380 | |
| 381 void serv_chat_leave(GaimConnection *g, int id) | |
| 382 { | |
| 383 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 384 | |
| 385 if (g->prpl != NULL) | |
| 386 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
| 387 | |
| 388 if (prpl_info && prpl_info->chat_leave) | |
| 389 prpl_info->chat_leave(g, id); | |
| 390 } | |
| 391 | |
| 392 void serv_chat_whisper(GaimConnection *g, int id, const char *who, const char *message) | |
| 393 { | |
| 394 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 395 | |
| 396 if (g != NULL && g->prpl != NULL) | |
| 397 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); | |
| 398 | |
| 399 if (prpl_info && prpl_info->chat_whisper) | |
| 400 prpl_info->chat_whisper(g, id, who, message); | |
| 401 } | |
| 402 | |
| 403 int serv_chat_send(GaimConnection *gc, int id, const char *message, GaimMessageFlags flags) | |
| 404 { | |
| 405 int val = -EINVAL; | |
| 406 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 407 | |
| 408 if (gc->prpl != NULL) | |
| 409 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
| 410 | |
| 411 if (prpl_info && prpl_info->chat_send) | |
| 412 val = prpl_info->chat_send(gc, id, message, flags); | |
| 413 | |
| 414 return val; | |
| 415 } | |
| 416 | |
| 417 /* | |
| 418 * woo. i'm actually going to comment this function. isn't that fun. make | |
| 419 * sure to follow along, kids | |
| 420 */ | |
| 421 void serv_got_im(GaimConnection *gc, const char *who, const char *msg, | |
| 422 GaimMessageFlags flags, time_t mtime) | |
| 423 { | |
| 424 GaimAccount *account; | |
| 425 GaimConversation *cnv; | |
| 426 char *message, *name; | |
| 427 char *angel, *buffy; | |
| 428 int plugin_return; | |
| 429 | |
| 430 g_return_if_fail(msg != NULL); | |
| 431 | |
| 432 account = gaim_connection_get_account(gc); | |
| 433 | |
| 434 if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->set_permit_deny == NULL) { | |
| 435 /* protocol does not support privacy, handle it ourselves */ | |
| 436 if (!gaim_privacy_check(account, who)) | |
| 437 return; | |
| 438 } | |
| 439 | |
| 440 /* | |
| 441 * We should update the conversation window buttons and menu, | |
| 442 * if it exists. | |
| 443 */ | |
| 444 cnv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, who, gc->account); | |
| 445 | |
| 446 /* | |
| 447 * Plugin stuff. we pass a char ** but we don't want to pass what's | |
| 448 * been given us by the prpls. So we create temp holders and pass | |
| 449 * those instead. It's basically just to avoid segfaults. | |
| 450 */ | |
| 451 buffy = g_malloc(MAX(strlen(msg) + 1, BUF_LONG)); | |
| 452 strcpy(buffy, msg); | |
| 453 angel = g_strdup(who); | |
| 454 | |
| 455 plugin_return = GPOINTER_TO_INT( | |
| 456 gaim_signal_emit_return_1(gaim_conversations_get_handle(), | |
| 457 "receiving-im-msg", gc->account, | |
| 458 &angel, &buffy, cnv, &flags)); | |
| 459 | |
| 460 if (!buffy || !angel || plugin_return) { | |
| 461 g_free(buffy); | |
| 462 g_free(angel); | |
| 463 return; | |
| 464 } | |
| 465 | |
| 466 name = angel; | |
| 467 message = buffy; | |
| 468 | |
| 469 gaim_signal_emit(gaim_conversations_get_handle(), "received-im-msg", gc->account, | |
| 470 name, message, cnv, flags); | |
| 471 | |
| 472 /* search for conversation again in case it was created by received-im-msg handler */ | |
| 473 if (cnv == NULL) | |
| 474 cnv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, gc->account); | |
| 475 | |
| 476 /* Make sure URLs are clickable */ | |
| 477 buffy = gaim_markup_linkify(message); | |
| 478 g_free(message); | |
| 479 message = buffy; | |
| 480 | |
| 481 /* | |
| 482 * XXX: Should we be setting this here, or relying on prpls to set it? | |
| 483 */ | |
| 484 flags |= GAIM_MESSAGE_RECV; | |
| 485 | |
| 486 if (cnv == NULL) | |
| 487 cnv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, name); | |
| 488 | |
| 489 gaim_conv_im_write(GAIM_CONV_IM(cnv), NULL, message, flags, mtime); | |
| 490 g_free(message); | |
| 491 | |
| 492 /* | |
| 493 * Don't autorespond if: | |
| 494 * | |
| 495 * - it's not supported on this connection | |
| 496 * - we are available | |
| 497 * - or it's disabled | |
| 498 * - or we're not idle and the 'only auto respond if idle' pref | |
| 499 * is set | |
| 500 */ | |
| 501 if (gc->flags & GAIM_CONNECTION_AUTO_RESP) | |
| 502 { | |
| 503 GaimPresence *presence; | |
| 504 GaimStatus *status; | |
| 505 GaimStatusType *status_type; | |
| 506 GaimStatusPrimitive primitive; | |
| 507 const gchar *auto_reply_pref; | |
| 508 const char *away_msg = NULL; | |
| 509 | |
| 510 auto_reply_pref = gaim_prefs_get_string("/core/away/auto_reply"); | |
| 511 | |
| 512 presence = gaim_account_get_presence(account); | |
| 513 status = gaim_presence_get_active_status(presence); | |
| 514 status_type = gaim_status_get_type(status); | |
| 515 primitive = gaim_status_type_get_primitive(status_type); | |
| 516 if ((primitive == GAIM_STATUS_AVAILABLE) || | |
| 517 (primitive == GAIM_STATUS_INVISIBLE) || | |
| 518 (primitive == GAIM_STATUS_MOBILE) || | |
| 519 !strcmp(auto_reply_pref, "never") || | |
| 520 (!gaim_presence_is_idle(presence) && !strcmp(auto_reply_pref, "awayidle"))) | |
| 521 { | |
| 522 g_free(name); | |
| 523 return; | |
| 524 } | |
| 525 | |
| 526 away_msg = gaim_value_get_string( | |
| 527 gaim_status_get_attr_value(status, "message")); | |
| 528 | |
| 529 if ((away_msg != NULL) && (*away_msg != '\0')) { | |
| 530 struct last_auto_response *lar; | |
| 531 time_t now = time(NULL); | |
| 532 | |
| 533 /* | |
| 534 * This used to be based on the conversation window. But um, if | |
| 535 * you went away, and someone sent you a message and got your | |
| 536 * auto-response, and then you closed the window, and then they | |
| 537 * sent you another one, they'd get the auto-response back too | |
| 538 * soon. Besides that, we need to keep track of this even if we've | |
| 539 * got a queue. So the rest of this block is just the auto-response, | |
| 540 * if necessary. | |
| 541 */ | |
| 542 lar = get_last_auto_response(gc, name); | |
| 543 if ((now - lar->sent) >= SECS_BEFORE_RESENDING_AUTORESPONSE) | |
| 544 { | |
| 545 /* | |
| 546 * We don't want to send an autoresponse in response to the other user's | |
| 547 * autoresponse. We do, however, not want to then send one in response to the | |
| 548 * _next_ message, so we still set lar->sent to now. | |
| 549 */ | |
| 550 lar->sent = now; | |
| 551 | |
| 552 if (!(flags & GAIM_MESSAGE_AUTO_RESP)) | |
| 553 { | |
| 554 serv_send_im(gc, name, away_msg, GAIM_MESSAGE_AUTO_RESP); | |
| 555 | |
| 556 gaim_conv_im_write(GAIM_CONV_IM(cnv), NULL, away_msg, | |
| 557 GAIM_MESSAGE_SEND | GAIM_MESSAGE_AUTO_RESP, | |
| 558 mtime); | |
| 559 } | |
| 560 } | |
| 561 } | |
| 562 } | |
| 563 | |
| 564 g_free(name); | |
| 565 } | |
| 566 | |
| 567 void serv_got_typing(GaimConnection *gc, const char *name, int timeout, | |
| 568 GaimTypingState state) { | |
| 569 GaimConversation *conv; | |
| 570 GaimConvIm *im = NULL; | |
| 571 | |
| 572 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, gc->account); | |
| 573 if (conv != NULL) { | |
| 574 im = GAIM_CONV_IM(conv); | |
| 575 | |
| 576 gaim_conv_im_set_typing_state(im, state); | |
| 577 gaim_conv_im_update_typing(im); | |
| 578 } else { | |
| 579 if (state == GAIM_TYPING) | |
| 580 { | |
| 581 gaim_signal_emit(gaim_conversations_get_handle(), | |
| 582 "buddy-typing", gc->account, name); | |
| 583 } | |
| 584 else | |
| 585 { | |
| 586 gaim_signal_emit(gaim_conversations_get_handle(), | |
| 587 "buddy-typed", gc->account, name); | |
| 588 } | |
| 589 } | |
| 590 | |
| 591 if (conv != NULL && timeout > 0) | |
| 592 gaim_conv_im_start_typing_timeout(im, timeout); | |
| 593 } | |
| 594 | |
| 595 void serv_got_typing_stopped(GaimConnection *gc, const char *name) { | |
| 596 | |
| 597 GaimConversation *conv; | |
| 598 GaimConvIm *im; | |
| 599 | |
| 600 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, gc->account); | |
| 601 if (conv != NULL) | |
| 602 { | |
| 603 im = GAIM_CONV_IM(conv); | |
| 604 | |
| 605 if (im->typing_state == GAIM_NOT_TYPING) | |
| 606 return; | |
| 607 | |
| 608 gaim_conv_im_stop_typing_timeout(im); | |
| 609 gaim_conv_im_set_typing_state(im, GAIM_NOT_TYPING); | |
| 610 gaim_conv_im_update_typing(im); | |
| 611 } | |
| 612 else | |
| 613 { | |
| 614 gaim_signal_emit(gaim_conversations_get_handle(), | |
| 615 "buddy-typing-stopped", gc->account, name); | |
| 616 } | |
| 617 } | |
| 618 | |
| 619 struct chat_invite_data { | |
| 620 GaimConnection *gc; | |
| 621 GHashTable *components; | |
| 622 }; | |
| 623 | |
| 624 static void chat_invite_data_free(struct chat_invite_data *cid) | |
| 625 { | |
| 626 if (cid->components) | |
| 627 g_hash_table_destroy(cid->components); | |
| 628 g_free(cid); | |
| 629 } | |
| 630 | |
| 631 | |
| 632 static void chat_invite_reject(struct chat_invite_data *cid) | |
| 633 { | |
| 634 serv_reject_chat(cid->gc, cid->components); | |
| 635 chat_invite_data_free(cid); | |
| 636 } | |
| 637 | |
| 638 | |
| 639 static void chat_invite_accept(struct chat_invite_data *cid) | |
| 640 { | |
| 641 serv_join_chat(cid->gc, cid->components); | |
| 642 chat_invite_data_free(cid); | |
| 643 } | |
| 644 | |
| 645 | |
| 646 | |
| 647 void serv_got_chat_invite(GaimConnection *gc, const char *name, | |
| 648 const char *who, const char *message, GHashTable *data) | |
| 649 { | |
| 650 GaimAccount *account; | |
| 651 char buf2[BUF_LONG]; | |
| 652 struct chat_invite_data *cid = g_new0(struct chat_invite_data, 1); | |
| 653 int plugin_return; | |
| 654 | |
| 655 account = gaim_connection_get_account(gc); | |
| 656 if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->set_permit_deny == NULL) { | |
| 657 /* protocol does not support privacy, handle it ourselves */ | |
| 658 if (!gaim_privacy_check(account, who)) | |
| 659 return; | |
| 660 } | |
| 661 | |
| 662 plugin_return = GPOINTER_TO_INT(gaim_signal_emit_return_1( | |
| 663 gaim_conversations_get_handle(), | |
| 664 "chat-invited", account, who, name, message, data)); | |
| 665 | |
| 666 cid->gc = gc; | |
| 667 cid->components = data; | |
| 668 | |
| 669 if (plugin_return == 0) | |
| 670 { | |
| 671 if (message != NULL) | |
| 672 { | |
| 673 g_snprintf(buf2, sizeof(buf2), | |
| 674 _("%s has invited %s to the chat room %s:\n%s"), | |
| 675 who, gaim_account_get_username(account), name, message); | |
| 676 } | |
| 677 else | |
| 678 g_snprintf(buf2, sizeof(buf2), | |
| 679 _("%s has invited %s to the chat room %s\n"), | |
| 680 who, gaim_account_get_username(account), name); | |
| 681 | |
| 682 | |
| 683 gaim_request_accept_cancel(gc, NULL, _("Accept chat invitation?"), buf2, | |
| 684 GAIM_DEFAULT_ACTION_NONE, cid, | |
| 685 G_CALLBACK(chat_invite_accept), | |
| 686 G_CALLBACK(chat_invite_reject)); | |
| 687 } | |
| 688 else if (plugin_return > 0) | |
| 689 chat_invite_accept(cid); | |
| 690 else | |
| 691 chat_invite_reject(cid); | |
| 692 } | |
| 693 | |
| 694 GaimConversation *serv_got_joined_chat(GaimConnection *gc, | |
| 695 int id, const char *name) | |
| 696 { | |
| 697 GaimConversation *conv; | |
| 698 GaimConvChat *chat; | |
| 699 GaimAccount *account; | |
| 700 | |
| 701 account = gaim_connection_get_account(gc); | |
| 702 | |
| 703 conv = gaim_conversation_new(GAIM_CONV_TYPE_CHAT, account, name); | |
| 704 chat = GAIM_CONV_CHAT(conv); | |
| 705 | |
| 706 if (!g_slist_find(gc->buddy_chats, conv)) | |
| 707 gc->buddy_chats = g_slist_append(gc->buddy_chats, conv); | |
| 708 | |
| 709 gaim_conv_chat_set_id(chat, id); | |
| 710 | |
| 711 gaim_signal_emit(gaim_conversations_get_handle(), "chat-joined", conv); | |
| 712 | |
| 713 return conv; | |
| 714 } | |
| 715 | |
| 716 void serv_got_chat_left(GaimConnection *g, int id) | |
| 717 { | |
| 718 GSList *bcs; | |
| 719 GaimConversation *conv = NULL; | |
| 720 GaimConvChat *chat = NULL; | |
| 721 | |
| 722 for (bcs = g->buddy_chats; bcs != NULL; bcs = bcs->next) { | |
| 723 conv = (GaimConversation *)bcs->data; | |
| 724 | |
| 725 chat = GAIM_CONV_CHAT(conv); | |
| 726 | |
| 727 if (gaim_conv_chat_get_id(chat) == id) | |
| 728 break; | |
| 729 | |
| 730 conv = NULL; | |
| 731 } | |
| 732 | |
| 733 if (!conv) | |
| 734 return; | |
| 735 | |
| 736 gaim_debug(GAIM_DEBUG_INFO, "server", "Leaving room: %s\n", | |
| 737 gaim_conversation_get_name(conv)); | |
| 738 | |
| 739 g->buddy_chats = g_slist_remove(g->buddy_chats, conv); | |
| 740 | |
| 741 gaim_conv_chat_left(GAIM_CONV_CHAT(conv)); | |
| 742 | |
| 743 gaim_signal_emit(gaim_conversations_get_handle(), "chat-left", conv); | |
| 744 } | |
| 745 | |
| 746 void serv_got_chat_in(GaimConnection *g, int id, const char *who, | |
| 747 GaimMessageFlags flags, const char *message, time_t mtime) | |
| 748 { | |
| 749 GSList *bcs; | |
| 750 GaimConversation *conv = NULL; | |
| 751 GaimConvChat *chat = NULL; | |
| 752 char *buf; | |
| 753 char *buffy, *angel; | |
| 754 int plugin_return; | |
| 755 | |
| 756 g_return_if_fail(who != NULL); | |
| 757 g_return_if_fail(message != NULL); | |
| 758 | |
| 759 for (bcs = g->buddy_chats; bcs != NULL; bcs = bcs->next) { | |
| 760 conv = (GaimConversation *)bcs->data; | |
| 761 | |
| 762 chat = GAIM_CONV_CHAT(conv); | |
| 763 | |
| 764 if (gaim_conv_chat_get_id(chat) == id) | |
| 765 break; | |
| 766 | |
| 767 conv = NULL; | |
| 768 } | |
| 769 | |
| 770 if (!conv) | |
| 771 return; | |
| 772 | |
| 773 /* | |
| 774 * Plugin stuff. We pass a char ** but we don't want to pass what's | |
| 775 * been given us by the prpls. so we create temp holders and pass those | |
| 776 * instead. It's basically just to avoid segfaults. Of course, if the | |
| 777 * data is binary, plugins don't see it. Bitch all you want; i really | |
| 778 * don't want you to be dealing with it. | |
| 779 */ | |
| 780 | |
| 781 buffy = g_malloc(MAX(strlen(message) + 1, BUF_LONG)); | |
| 782 strcpy(buffy, message); | |
| 783 angel = g_strdup(who); | |
| 784 | |
| 785 plugin_return = GPOINTER_TO_INT( | |
| 786 gaim_signal_emit_return_1(gaim_conversations_get_handle(), | |
| 787 "receiving-chat-msg", g->account, | |
| 788 &angel, &buffy, conv, &flags)); | |
| 789 | |
| 790 if (!buffy || !angel || plugin_return) { | |
| 791 g_free(buffy); | |
| 792 g_free(angel); | |
| 793 return; | |
| 794 } | |
| 795 who = angel; | |
| 796 message = buffy; | |
| 797 | |
| 798 gaim_signal_emit(gaim_conversations_get_handle(), "received-chat-msg", g->account, | |
| 799 who, message, conv, flags); | |
| 800 | |
| 801 /* Make sure URLs are clickable */ | |
| 802 buf = gaim_markup_linkify(message); | |
| 803 | |
| 804 gaim_conv_chat_write(chat, who, buf, flags, mtime); | |
| 805 | |
| 806 g_free(angel); | |
| 807 g_free(buf); | |
| 808 g_free(buffy); | |
| 809 } | |
| 810 | |
| 811 void serv_send_file(GaimConnection *gc, const char *who, const char *file) | |
| 812 { | |
| 813 GaimPluginProtocolInfo *prpl_info = NULL; | |
| 814 | |
| 815 if (gc != NULL && gc->prpl != NULL) | |
| 816 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); | |
| 817 | |
| 818 if (prpl_info && prpl_info->send_file) { | |
| 819 if (!prpl_info->can_receive_file || prpl_info->can_receive_file(gc, who)) { | |
| 820 prpl_info->send_file(gc, who, file); | |
| 821 } | |
| 822 } | |
| 823 } |
