| 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 |
|
| 176 if (prpl_info && g_list_find(gaim_connections_get_all(), gc) && |
|
| 177 prpl_info->set_info) { |
|
| 178 |
|
| 179 account = gaim_connection_get_account(gc); |
|
| 180 |
|
| 181 if (gaim_signal_emit_return_1(gaim_accounts_get_handle(), |
|
| 182 "account-setting-info", account, info)) |
|
| 183 return; |
|
| 184 |
|
| 185 prpl_info->set_info(gc, info); |
|
| 186 |
|
| 187 gaim_signal_emit(gaim_accounts_get_handle(), |
|
| 188 "account-set-info", account, info); |
|
| 189 } |
|
| 190 } |
|
| 191 |
|
| 192 /* |
|
| 193 * Set buddy's alias on server roster/list |
|
| 194 */ |
|
| 195 void serv_alias_buddy(GaimBuddy *b) |
|
| 196 { |
|
| 197 GaimPluginProtocolInfo *prpl_info = NULL; |
|
| 198 |
|
| 199 if (b != NULL && b->account->gc->prpl != NULL) |
|
| 200 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(b->account->gc->prpl); |
|
| 201 |
|
| 202 if (b && prpl_info && prpl_info->alias_buddy) { |
|
| 203 prpl_info->alias_buddy(b->account->gc, b->name, b->alias); |
|
| 204 } |
|
| 205 } |
|
| 206 |
|
| 207 void |
|
| 208 serv_got_alias(GaimConnection *gc, const char *who, const char *alias) |
|
| 209 { |
|
| 210 GaimAccount *account = gaim_connection_get_account(gc); |
|
| 211 GSList *buds, *buddies = gaim_find_buddies(account, who); |
|
| 212 GaimBuddy *b; |
|
| 213 GaimConversation *conv; |
|
| 214 |
|
| 215 for (buds = buddies; buds; buds = buds->next) |
|
| 216 { |
|
| 217 b = buds->data; |
|
| 218 gaim_blist_server_alias_buddy(b, alias); |
|
| 219 |
|
| 220 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, b->name, account); |
|
| 221 |
|
| 222 if (conv != NULL && b->server_alias != NULL && |
|
| 223 strcmp(b->server_alias, alias)) |
|
| 224 { |
|
| 225 char *tmp = g_strdup_printf(_("%s is now known as %s.\n"), |
|
| 226 who, alias); |
|
| 227 |
|
| 228 gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, |
|
| 229 time(NULL)); |
|
| 230 |
|
| 231 g_free(tmp); |
|
| 232 } |
|
| 233 } |
|
| 234 g_slist_free(buddies); |
|
| 235 } |
|
| 236 |
|
| 237 /* |
|
| 238 * Move a buddy from one group to another on server. |
|
| 239 * |
|
| 240 * Note: For now we'll not deal with changing gc's at the same time, but |
|
| 241 * it should be possible. Probably needs to be done, someday. Although, |
|
| 242 * the UI for that would be difficult, because groups are Gaim-wide. |
|
| 243 */ |
|
| 244 void serv_move_buddy(GaimBuddy *b, GaimGroup *og, GaimGroup *ng) |
|
| 245 { |
|
| 246 GaimPluginProtocolInfo *prpl_info = NULL; |
|
| 247 |
|
| 248 g_return_if_fail(b != NULL); |
|
| 249 g_return_if_fail(og != NULL); |
|
| 250 g_return_if_fail(ng != NULL); |
|
| 251 |
|
| 252 if (b->account->gc != NULL && b->account->gc->prpl != NULL) |
|
| 253 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(b->account->gc->prpl); |
|
| 254 |
|
| 255 if (b->account->gc && og && ng) { |
|
| 256 if (prpl_info && prpl_info->group_buddy) { |
|
| 257 prpl_info->group_buddy(b->account->gc, b->name, og->name, ng->name); |
|
| 258 } |
|
| 259 } |
|
| 260 } |
|
| 261 |
|
| 262 void serv_add_permit(GaimConnection *g, const char *name) |
|
| 263 { |
|
| 264 GaimPluginProtocolInfo *prpl_info = NULL; |
|
| 265 |
|
| 266 if (g != NULL && g->prpl != NULL) |
|
| 267 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); |
|
| 268 |
|
| 269 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->add_permit) |
|
| 270 prpl_info->add_permit(g, name); |
|
| 271 } |
|
| 272 |
|
| 273 void serv_add_deny(GaimConnection *g, const char *name) |
|
| 274 { |
|
| 275 GaimPluginProtocolInfo *prpl_info = NULL; |
|
| 276 |
|
| 277 if (g != NULL && g->prpl != NULL) |
|
| 278 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); |
|
| 279 |
|
| 280 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->add_deny) |
|
| 281 prpl_info->add_deny(g, name); |
|
| 282 } |
|
| 283 |
|
| 284 void serv_rem_permit(GaimConnection *g, const char *name) |
|
| 285 { |
|
| 286 GaimPluginProtocolInfo *prpl_info = NULL; |
|
| 287 |
|
| 288 if (g != NULL && g->prpl != NULL) |
|
| 289 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); |
|
| 290 |
|
| 291 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->rem_permit) |
|
| 292 prpl_info->rem_permit(g, name); |
|
| 293 } |
|
| 294 |
|
| 295 void serv_rem_deny(GaimConnection *g, const char *name) |
|
| 296 { |
|
| 297 GaimPluginProtocolInfo *prpl_info = NULL; |
|
| 298 |
|
| 299 if (g != NULL && g->prpl != NULL) |
|
| 300 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); |
|
| 301 |
|
| 302 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->rem_deny) |
|
| 303 prpl_info->rem_deny(g, name); |
|
| 304 } |
|
| 305 |
|
| 306 void serv_set_permit_deny(GaimConnection *g) |
|
| 307 { |
|
| 308 GaimPluginProtocolInfo *prpl_info = NULL; |
|
| 309 |
|
| 310 if (g != NULL && g->prpl != NULL) |
|
| 311 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); |
|
| 312 |
|
| 313 /* |
|
| 314 * this is called when either you import a buddy list, and make lots |
|
| 315 * of changes that way, or when the user toggles the permit/deny mode |
|
| 316 * in the prefs. In either case you should probably be resetting and |
|
| 317 * resending the permit/deny info when you get this. |
|
| 318 */ |
|
| 319 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->set_permit_deny) |
|
| 320 prpl_info->set_permit_deny(g); |
|
| 321 } |
|
| 322 |
|
| 323 void serv_join_chat(GaimConnection *g, GHashTable *data) |
|
| 324 { |
|
| 325 GaimPluginProtocolInfo *prpl_info = NULL; |
|
| 326 |
|
| 327 if (g != NULL && g->prpl != NULL) |
|
| 328 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); |
|
| 329 |
|
| 330 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->join_chat) |
|
| 331 prpl_info->join_chat(g, data); |
|
| 332 } |
|
| 333 |
|
| 334 |
|
| 335 void serv_reject_chat(GaimConnection *g, GHashTable *data) |
|
| 336 { |
|
| 337 GaimPluginProtocolInfo *prpl_info = NULL; |
|
| 338 |
|
| 339 if (g != NULL && g->prpl != NULL) |
|
| 340 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); |
|
| 341 |
|
| 342 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->reject_chat) |
|
| 343 prpl_info->reject_chat(g, data); |
|
| 344 } |
|
| 345 |
|
| 346 void serv_chat_invite(GaimConnection *g, int id, const char *message, const char *name) |
|
| 347 { |
|
| 348 GaimPluginProtocolInfo *prpl_info = NULL; |
|
| 349 GaimConversation *conv; |
|
| 350 char *buffy = message && *message ? g_strdup(message) : NULL; |
|
| 351 |
|
| 352 conv = gaim_find_chat(g, id); |
|
| 353 |
|
| 354 if (conv == NULL) |
|
| 355 return; |
|
| 356 |
|
| 357 if (g != NULL && g->prpl != NULL) |
|
| 358 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(g->prpl); |
|
| 359 |
|
| 360 gaim_signal_emit(gaim_conversations_get_handle(), "chat-inviting-user", |
|
| 361 conv, name, &buffy); |
|
| 362 |
|
| 363 if (prpl_info && g_list_find(gaim_connections_get_all(), g) && prpl_info->chat_invite) |
|
| 364 prpl_info->chat_invite(g, id, buffy, name); |
|
| 365 |
|
| 366 gaim_signal_emit(gaim_conversations_get_handle(), "chat-invited-user", |
|
| 367 conv, name, buffy); |
|
| 368 |
|
| 369 g_free(buffy); |
|
| 370 } |
|
| 371 |
|
| 372 /* Ya know, nothing uses this except gaim_conversation_destroy(), |
|
| 373 * I think I'll just merge it into that later... |
|
| 374 * Then again, something might want to use this, from outside prpl-land |
|
| 375 * to leave a chat without destroying the conversation. |
|
| 376 */ |
|
| 377 |
|
| 378 void serv_chat_leave(GaimConnection *g, int id) |
|
| 379 { |
|
| 380 GaimPluginProtocolInfo *prpl_info = NULL; |
|
| 381 |
|
| 382 if (!g_list_find(gaim_connections_get_all(), g)) |
|
| 383 return; |
|
| 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 void serv_set_buddyicon(GaimConnection *gc, const char *filename) |
|
| 418 { |
|
| 419 GaimPluginProtocolInfo *prpl_info = NULL; |
|
| 420 |
|
| 421 if (gc->prpl != NULL) |
|
| 422 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); |
|
| 423 |
|
| 424 if (prpl_info && prpl_info->set_buddy_icon) |
|
| 425 prpl_info->set_buddy_icon(gc, filename); |
|
| 426 |
|
| 427 } |
|
| 428 |
|
| 429 /* |
|
| 430 * woo. i'm actually going to comment this function. isn't that fun. make |
|
| 431 * sure to follow along, kids |
|
| 432 */ |
|
| 433 void serv_got_im(GaimConnection *gc, const char *who, const char *msg, |
|
| 434 GaimMessageFlags flags, time_t mtime) |
|
| 435 { |
|
| 436 GaimAccount *account; |
|
| 437 GaimConversation *cnv; |
|
| 438 char *message, *name; |
|
| 439 char *angel, *buffy; |
|
| 440 int plugin_return; |
|
| 441 |
|
| 442 g_return_if_fail(msg != NULL); |
|
| 443 |
|
| 444 account = gaim_connection_get_account(gc); |
|
| 445 |
|
| 446 if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->set_permit_deny == NULL) { |
|
| 447 /* protocol does not support privacy, handle it ourselves */ |
|
| 448 if (!gaim_privacy_check(account, who)) |
|
| 449 return; |
|
| 450 } |
|
| 451 |
|
| 452 /* |
|
| 453 * We should update the conversation window buttons and menu, |
|
| 454 * if it exists. |
|
| 455 */ |
|
| 456 cnv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, who, gc->account); |
|
| 457 |
|
| 458 /* |
|
| 459 * Plugin stuff. we pass a char ** but we don't want to pass what's |
|
| 460 * been given us by the prpls. So we create temp holders and pass |
|
| 461 * those instead. It's basically just to avoid segfaults. |
|
| 462 */ |
|
| 463 buffy = g_malloc(MAX(strlen(msg) + 1, BUF_LONG)); |
|
| 464 strcpy(buffy, msg); |
|
| 465 angel = g_strdup(who); |
|
| 466 |
|
| 467 plugin_return = GPOINTER_TO_INT( |
|
| 468 gaim_signal_emit_return_1(gaim_conversations_get_handle(), |
|
| 469 "receiving-im-msg", gc->account, |
|
| 470 &angel, &buffy, cnv, &flags)); |
|
| 471 |
|
| 472 if (!buffy || !angel || plugin_return) { |
|
| 473 g_free(buffy); |
|
| 474 g_free(angel); |
|
| 475 return; |
|
| 476 } |
|
| 477 |
|
| 478 name = angel; |
|
| 479 message = buffy; |
|
| 480 |
|
| 481 gaim_signal_emit(gaim_conversations_get_handle(), "received-im-msg", gc->account, |
|
| 482 name, message, cnv, flags); |
|
| 483 |
|
| 484 /* search for conversation again in case it was created by received-im-msg handler */ |
|
| 485 if (cnv == NULL) |
|
| 486 cnv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, gc->account); |
|
| 487 |
|
| 488 /* Make sure URLs are clickable */ |
|
| 489 buffy = gaim_markup_linkify(message); |
|
| 490 g_free(message); |
|
| 491 message = buffy; |
|
| 492 |
|
| 493 /* |
|
| 494 * XXX: Should we be setting this here, or relying on prpls to set it? |
|
| 495 */ |
|
| 496 flags |= GAIM_MESSAGE_RECV; |
|
| 497 |
|
| 498 if (cnv == NULL) |
|
| 499 cnv = gaim_conversation_new(GAIM_CONV_TYPE_IM, account, name); |
|
| 500 |
|
| 501 gaim_conv_im_write(GAIM_CONV_IM(cnv), NULL, message, flags, mtime); |
|
| 502 g_free(message); |
|
| 503 |
|
| 504 /* |
|
| 505 * Don't autorespond if: |
|
| 506 * |
|
| 507 * - it's not supported on this connection |
|
| 508 * - we are available |
|
| 509 * - or it's disabled |
|
| 510 * - or we're not idle and the 'only auto respond if idle' pref |
|
| 511 * is set |
|
| 512 */ |
|
| 513 if (gc->flags & GAIM_CONNECTION_AUTO_RESP) |
|
| 514 { |
|
| 515 GaimPresence *presence; |
|
| 516 GaimStatus *status; |
|
| 517 GaimStatusType *status_type; |
|
| 518 GaimStatusPrimitive primitive; |
|
| 519 const gchar *auto_reply_pref; |
|
| 520 const char *away_msg = NULL; |
|
| 521 |
|
| 522 auto_reply_pref = gaim_prefs_get_string("/core/away/auto_reply"); |
|
| 523 |
|
| 524 presence = gaim_account_get_presence(account); |
|
| 525 status = gaim_presence_get_active_status(presence); |
|
| 526 status_type = gaim_status_get_type(status); |
|
| 527 primitive = gaim_status_type_get_primitive(status_type); |
|
| 528 if ((primitive == GAIM_STATUS_AVAILABLE) || |
|
| 529 (primitive == GAIM_STATUS_INVISIBLE) || |
|
| 530 (primitive == GAIM_STATUS_MOBILE) || |
|
| 531 !strcmp(auto_reply_pref, "never") || |
|
| 532 (!gaim_presence_is_idle(presence) && !strcmp(auto_reply_pref, "awayidle"))) |
|
| 533 { |
|
| 534 g_free(name); |
|
| 535 return; |
|
| 536 } |
|
| 537 |
|
| 538 away_msg = gaim_value_get_string( |
|
| 539 gaim_status_get_attr_value(status, "message")); |
|
| 540 |
|
| 541 if ((away_msg != NULL) && (*away_msg != '\0')) { |
|
| 542 struct last_auto_response *lar; |
|
| 543 time_t now = time(NULL); |
|
| 544 |
|
| 545 /* |
|
| 546 * This used to be based on the conversation window. But um, if |
|
| 547 * you went away, and someone sent you a message and got your |
|
| 548 * auto-response, and then you closed the window, and then they |
|
| 549 * sent you another one, they'd get the auto-response back too |
|
| 550 * soon. Besides that, we need to keep track of this even if we've |
|
| 551 * got a queue. So the rest of this block is just the auto-response, |
|
| 552 * if necessary. |
|
| 553 */ |
|
| 554 lar = get_last_auto_response(gc, name); |
|
| 555 if ((now - lar->sent) >= SECS_BEFORE_RESENDING_AUTORESPONSE) |
|
| 556 { |
|
| 557 /* |
|
| 558 * We don't want to send an autoresponse in response to the other user's |
|
| 559 * autoresponse. We do, however, not want to then send one in response to the |
|
| 560 * _next_ message, so we still set lar->sent to now. |
|
| 561 */ |
|
| 562 lar->sent = now; |
|
| 563 |
|
| 564 if (!(flags & GAIM_MESSAGE_AUTO_RESP)) |
|
| 565 { |
|
| 566 serv_send_im(gc, name, away_msg, GAIM_MESSAGE_AUTO_RESP); |
|
| 567 |
|
| 568 gaim_conv_im_write(GAIM_CONV_IM(cnv), NULL, away_msg, |
|
| 569 GAIM_MESSAGE_SEND | GAIM_MESSAGE_AUTO_RESP, |
|
| 570 mtime); |
|
| 571 } |
|
| 572 } |
|
| 573 } |
|
| 574 } |
|
| 575 |
|
| 576 g_free(name); |
|
| 577 } |
|
| 578 |
|
| 579 void serv_got_typing(GaimConnection *gc, const char *name, int timeout, |
|
| 580 GaimTypingState state) { |
|
| 581 GaimConversation *conv; |
|
| 582 GaimConvIm *im = NULL; |
|
| 583 |
|
| 584 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, gc->account); |
|
| 585 if (conv != NULL) { |
|
| 586 im = GAIM_CONV_IM(conv); |
|
| 587 |
|
| 588 gaim_conv_im_set_typing_state(im, state); |
|
| 589 gaim_conv_im_update_typing(im); |
|
| 590 } else { |
|
| 591 if (state == GAIM_TYPING) |
|
| 592 { |
|
| 593 gaim_signal_emit(gaim_conversations_get_handle(), |
|
| 594 "buddy-typing", gc->account, name); |
|
| 595 } |
|
| 596 else |
|
| 597 { |
|
| 598 gaim_signal_emit(gaim_conversations_get_handle(), |
|
| 599 "buddy-typed", gc->account, name); |
|
| 600 } |
|
| 601 } |
|
| 602 |
|
| 603 if (conv != NULL && timeout > 0) |
|
| 604 gaim_conv_im_start_typing_timeout(im, timeout); |
|
| 605 } |
|
| 606 |
|
| 607 void serv_got_typing_stopped(GaimConnection *gc, const char *name) { |
|
| 608 |
|
| 609 GaimConversation *conv; |
|
| 610 GaimConvIm *im; |
|
| 611 |
|
| 612 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, name, gc->account); |
|
| 613 if (conv != NULL) |
|
| 614 { |
|
| 615 im = GAIM_CONV_IM(conv); |
|
| 616 |
|
| 617 if (im->typing_state == GAIM_NOT_TYPING) |
|
| 618 return; |
|
| 619 |
|
| 620 gaim_conv_im_stop_typing_timeout(im); |
|
| 621 gaim_conv_im_set_typing_state(im, GAIM_NOT_TYPING); |
|
| 622 gaim_conv_im_update_typing(im); |
|
| 623 } |
|
| 624 else |
|
| 625 { |
|
| 626 gaim_signal_emit(gaim_conversations_get_handle(), |
|
| 627 "buddy-typing-stopped", gc->account, name); |
|
| 628 } |
|
| 629 } |
|
| 630 |
|
| 631 struct chat_invite_data { |
|
| 632 GaimConnection *gc; |
|
| 633 GHashTable *components; |
|
| 634 }; |
|
| 635 |
|
| 636 static void chat_invite_data_free(struct chat_invite_data *cid) |
|
| 637 { |
|
| 638 if (cid->components) |
|
| 639 g_hash_table_destroy(cid->components); |
|
| 640 g_free(cid); |
|
| 641 } |
|
| 642 |
|
| 643 |
|
| 644 static void chat_invite_reject(struct chat_invite_data *cid) |
|
| 645 { |
|
| 646 serv_reject_chat(cid->gc, cid->components); |
|
| 647 chat_invite_data_free(cid); |
|
| 648 } |
|
| 649 |
|
| 650 |
|
| 651 static void chat_invite_accept(struct chat_invite_data *cid) |
|
| 652 { |
|
| 653 serv_join_chat(cid->gc, cid->components); |
|
| 654 chat_invite_data_free(cid); |
|
| 655 } |
|
| 656 |
|
| 657 |
|
| 658 |
|
| 659 void serv_got_chat_invite(GaimConnection *gc, const char *name, |
|
| 660 const char *who, const char *message, GHashTable *data) |
|
| 661 { |
|
| 662 GaimAccount *account; |
|
| 663 char buf2[BUF_LONG]; |
|
| 664 struct chat_invite_data *cid = g_new0(struct chat_invite_data, 1); |
|
| 665 int plugin_return; |
|
| 666 |
|
| 667 account = gaim_connection_get_account(gc); |
|
| 668 if (GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl)->set_permit_deny == NULL) { |
|
| 669 /* protocol does not support privacy, handle it ourselves */ |
|
| 670 if (!gaim_privacy_check(account, who)) |
|
| 671 return; |
|
| 672 } |
|
| 673 |
|
| 674 plugin_return = GPOINTER_TO_INT(gaim_signal_emit_return_1( |
|
| 675 gaim_conversations_get_handle(), |
|
| 676 "chat-invited", account, who, name, message, data)); |
|
| 677 |
|
| 678 cid->gc = gc; |
|
| 679 cid->components = data; |
|
| 680 |
|
| 681 if (plugin_return == 0) |
|
| 682 { |
|
| 683 if (message != NULL) |
|
| 684 { |
|
| 685 g_snprintf(buf2, sizeof(buf2), |
|
| 686 _("%s has invited %s to the chat room %s:\n%s"), |
|
| 687 who, gaim_account_get_username(account), name, message); |
|
| 688 } |
|
| 689 else |
|
| 690 g_snprintf(buf2, sizeof(buf2), |
|
| 691 _("%s has invited %s to the chat room %s\n"), |
|
| 692 who, gaim_account_get_username(account), name); |
|
| 693 |
|
| 694 |
|
| 695 gaim_request_accept_cancel(gc, NULL, _("Accept chat invitation?"), buf2, |
|
| 696 GAIM_DEFAULT_ACTION_NONE, cid, |
|
| 697 G_CALLBACK(chat_invite_accept), |
|
| 698 G_CALLBACK(chat_invite_reject)); |
|
| 699 } |
|
| 700 else if (plugin_return > 0) |
|
| 701 chat_invite_accept(cid); |
|
| 702 else |
|
| 703 chat_invite_reject(cid); |
|
| 704 } |
|
| 705 |
|
| 706 GaimConversation *serv_got_joined_chat(GaimConnection *gc, |
|
| 707 int id, const char *name) |
|
| 708 { |
|
| 709 GaimConversation *conv; |
|
| 710 GaimConvChat *chat; |
|
| 711 GaimAccount *account; |
|
| 712 |
|
| 713 account = gaim_connection_get_account(gc); |
|
| 714 |
|
| 715 conv = gaim_conversation_new(GAIM_CONV_TYPE_CHAT, account, name); |
|
| 716 chat = GAIM_CONV_CHAT(conv); |
|
| 717 |
|
| 718 if (!g_slist_find(gc->buddy_chats, conv)) |
|
| 719 gc->buddy_chats = g_slist_append(gc->buddy_chats, conv); |
|
| 720 |
|
| 721 gaim_conv_chat_set_id(chat, id); |
|
| 722 |
|
| 723 gaim_signal_emit(gaim_conversations_get_handle(), "chat-joined", conv); |
|
| 724 |
|
| 725 return conv; |
|
| 726 } |
|
| 727 |
|
| 728 void serv_got_chat_left(GaimConnection *g, int id) |
|
| 729 { |
|
| 730 GSList *bcs; |
|
| 731 GaimConversation *conv = NULL; |
|
| 732 GaimConvChat *chat = NULL; |
|
| 733 |
|
| 734 for (bcs = g->buddy_chats; bcs != NULL; bcs = bcs->next) { |
|
| 735 conv = (GaimConversation *)bcs->data; |
|
| 736 |
|
| 737 chat = GAIM_CONV_CHAT(conv); |
|
| 738 |
|
| 739 if (gaim_conv_chat_get_id(chat) == id) |
|
| 740 break; |
|
| 741 |
|
| 742 conv = NULL; |
|
| 743 } |
|
| 744 |
|
| 745 if (!conv) |
|
| 746 return; |
|
| 747 |
|
| 748 gaim_debug(GAIM_DEBUG_INFO, "server", "Leaving room: %s\n", |
|
| 749 gaim_conversation_get_name(conv)); |
|
| 750 |
|
| 751 g->buddy_chats = g_slist_remove(g->buddy_chats, conv); |
|
| 752 |
|
| 753 gaim_conv_chat_left(GAIM_CONV_CHAT(conv)); |
|
| 754 |
|
| 755 gaim_signal_emit(gaim_conversations_get_handle(), "chat-left", conv); |
|
| 756 } |
|
| 757 |
|
| 758 void serv_got_chat_in(GaimConnection *g, int id, const char *who, |
|
| 759 GaimMessageFlags flags, const char *message, time_t mtime) |
|
| 760 { |
|
| 761 GSList *bcs; |
|
| 762 GaimConversation *conv = NULL; |
|
| 763 GaimConvChat *chat = NULL; |
|
| 764 char *buf; |
|
| 765 char *buffy, *angel; |
|
| 766 int plugin_return; |
|
| 767 |
|
| 768 g_return_if_fail(who != NULL); |
|
| 769 g_return_if_fail(message != NULL); |
|
| 770 |
|
| 771 for (bcs = g->buddy_chats; bcs != NULL; bcs = bcs->next) { |
|
| 772 conv = (GaimConversation *)bcs->data; |
|
| 773 |
|
| 774 chat = GAIM_CONV_CHAT(conv); |
|
| 775 |
|
| 776 if (gaim_conv_chat_get_id(chat) == id) |
|
| 777 break; |
|
| 778 |
|
| 779 conv = NULL; |
|
| 780 } |
|
| 781 |
|
| 782 if (!conv) |
|
| 783 return; |
|
| 784 |
|
| 785 /* |
|
| 786 * Plugin stuff. We pass a char ** but we don't want to pass what's |
|
| 787 * been given us by the prpls. so we create temp holders and pass those |
|
| 788 * instead. It's basically just to avoid segfaults. Of course, if the |
|
| 789 * data is binary, plugins don't see it. Bitch all you want; i really |
|
| 790 * don't want you to be dealing with it. |
|
| 791 */ |
|
| 792 |
|
| 793 buffy = g_malloc(MAX(strlen(message) + 1, BUF_LONG)); |
|
| 794 strcpy(buffy, message); |
|
| 795 angel = g_strdup(who); |
|
| 796 |
|
| 797 plugin_return = GPOINTER_TO_INT( |
|
| 798 gaim_signal_emit_return_1(gaim_conversations_get_handle(), |
|
| 799 "receiving-chat-msg", g->account, |
|
| 800 &angel, &buffy, conv, &flags)); |
|
| 801 |
|
| 802 if (!buffy || !angel || plugin_return) { |
|
| 803 g_free(buffy); |
|
| 804 g_free(angel); |
|
| 805 return; |
|
| 806 } |
|
| 807 who = angel; |
|
| 808 message = buffy; |
|
| 809 |
|
| 810 gaim_signal_emit(gaim_conversations_get_handle(), "received-chat-msg", g->account, |
|
| 811 who, message, conv, flags); |
|
| 812 |
|
| 813 /* Make sure URLs are clickable */ |
|
| 814 buf = gaim_markup_linkify(message); |
|
| 815 |
|
| 816 gaim_conv_chat_write(chat, who, buf, flags, mtime); |
|
| 817 |
|
| 818 g_free(angel); |
|
| 819 g_free(buf); |
|
| 820 g_free(buffy); |
|
| 821 } |
|
| 822 |
|
| 823 void serv_send_file(GaimConnection *gc, const char *who, const char *file) |
|
| 824 { |
|
| 825 GaimPluginProtocolInfo *prpl_info = NULL; |
|
| 826 |
|
| 827 if (gc != NULL && gc->prpl != NULL) |
|
| 828 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl); |
|
| 829 |
|
| 830 if (prpl_info && prpl_info->send_file) { |
|
| 831 if (!prpl_info->can_receive_file || prpl_info->can_receive_file(gc, who)) { |
|
| 832 prpl_info->send_file(gc, who, file); |
|
| 833 } |
|
| 834 } |
|
| 835 } |
|