Fix crashes when filenames end up being NULL in some prpls.
[pidgin-git.git] / libpurple / prpl.c
blobbbb1ec66f0154ec4dee63f0a8c4f639e8607a352
1 /*
2 * purple
4 * Purple 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.
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
23 #include "internal.h"
24 #include "conversation.h"
25 #include "debug.h"
26 #include "network.h"
27 #include "notify.h"
28 #include "prpl.h"
29 #include "request.h"
30 #include "util.h"
32 /**************************************************************************/
33 /** @name Attention Type API */
34 /**************************************************************************/
35 PurpleAttentionType *
36 purple_attention_type_new(const char *ulname, const char *name,
37 const char *inc_desc, const char *out_desc)
39 PurpleAttentionType *attn = g_new0(PurpleAttentionType, 1);
41 purple_attention_type_set_name(attn, name);
42 purple_attention_type_set_incoming_desc(attn, inc_desc);
43 purple_attention_type_set_outgoing_desc(attn, out_desc);
44 purple_attention_type_set_unlocalized_name(attn, ulname);
46 return attn;
50 void
51 purple_attention_type_set_name(PurpleAttentionType *type, const char *name)
53 g_return_if_fail(type != NULL);
55 type->name = name;
58 void
59 purple_attention_type_set_incoming_desc(PurpleAttentionType *type, const char *desc)
61 g_return_if_fail(type != NULL);
63 type->incoming_description = desc;
66 void
67 purple_attention_type_set_outgoing_desc(PurpleAttentionType *type, const char *desc)
69 g_return_if_fail(type != NULL);
71 type->outgoing_description = desc;
74 void
75 purple_attention_type_set_icon_name(PurpleAttentionType *type, const char *name)
77 g_return_if_fail(type != NULL);
79 type->icon_name = name;
82 void
83 purple_attention_type_set_unlocalized_name(PurpleAttentionType *type, const char *ulname)
85 g_return_if_fail(type != NULL);
87 type->unlocalized_name = ulname;
90 const char *
91 purple_attention_type_get_name(const PurpleAttentionType *type)
93 g_return_val_if_fail(type != NULL, NULL);
95 return type->name;
98 const char *
99 purple_attention_type_get_incoming_desc(const PurpleAttentionType *type)
101 g_return_val_if_fail(type != NULL, NULL);
103 return type->incoming_description;
106 const char *
107 purple_attention_type_get_outgoing_desc(const PurpleAttentionType *type)
109 g_return_val_if_fail(type != NULL, NULL);
111 return type->outgoing_description;
114 const char *
115 purple_attention_type_get_icon_name(const PurpleAttentionType *type)
117 g_return_val_if_fail(type != NULL, NULL);
119 if(type->icon_name == NULL || *(type->icon_name) == '\0')
120 return NULL;
122 return type->icon_name;
125 const char *
126 purple_attention_type_get_unlocalized_name(const PurpleAttentionType *type)
128 g_return_val_if_fail(type != NULL, NULL);
130 return type->unlocalized_name;
133 /**************************************************************************/
134 /** @name Protocol Plugin API */
135 /**************************************************************************/
136 void
137 purple_prpl_got_account_idle(PurpleAccount *account, gboolean idle,
138 time_t idle_time)
140 g_return_if_fail(account != NULL);
141 g_return_if_fail(purple_account_is_connected(account));
143 purple_presence_set_idle(purple_account_get_presence(account),
144 idle, idle_time);
147 void
148 purple_prpl_got_account_login_time(PurpleAccount *account, time_t login_time)
150 PurplePresence *presence;
152 g_return_if_fail(account != NULL);
153 g_return_if_fail(purple_account_is_connected(account));
155 if (login_time == 0)
156 login_time = time(NULL);
158 presence = purple_account_get_presence(account);
160 purple_presence_set_login_time(presence, login_time);
163 void
164 purple_prpl_got_account_status(PurpleAccount *account, const char *status_id, ...)
166 PurplePresence *presence;
167 PurpleStatus *status;
168 va_list args;
170 g_return_if_fail(account != NULL);
171 g_return_if_fail(status_id != NULL);
172 g_return_if_fail(purple_account_is_connected(account));
174 presence = purple_account_get_presence(account);
175 status = purple_presence_get_status(presence, status_id);
177 g_return_if_fail(status != NULL);
179 va_start(args, status_id);
180 purple_status_set_active_with_attrs(status, TRUE, args);
181 va_end(args);
184 void
185 purple_prpl_got_user_idle(PurpleAccount *account, const char *name,
186 gboolean idle, time_t idle_time)
188 PurplePresence *presence;
189 GSList *list;
191 g_return_if_fail(account != NULL);
192 g_return_if_fail(name != NULL);
193 g_return_if_fail(purple_account_is_connected(account) || purple_account_is_connecting(account));
195 if ((list = purple_find_buddies(account, name)) == NULL)
196 return;
198 while (list) {
199 presence = purple_buddy_get_presence(list->data);
200 list = g_slist_delete_link(list, list);
201 purple_presence_set_idle(presence, idle, idle_time);
205 void
206 purple_prpl_got_user_login_time(PurpleAccount *account, const char *name,
207 time_t login_time)
209 GSList *list;
210 PurplePresence *presence;
212 g_return_if_fail(account != NULL);
213 g_return_if_fail(name != NULL);
215 if ((list = purple_find_buddies(account, name)) == NULL)
216 return;
218 if (login_time == 0)
219 login_time = time(NULL);
221 while (list) {
222 PurpleBuddy *buddy = list->data;
223 presence = purple_buddy_get_presence(buddy);
224 list = g_slist_delete_link(list, list);
226 if (purple_presence_get_login_time(presence) != login_time)
228 purple_presence_set_login_time(presence, login_time);
230 purple_signal_emit(purple_blist_get_handle(), "buddy-got-login-time", buddy);
235 void
236 purple_prpl_got_user_status(PurpleAccount *account, const char *name,
237 const char *status_id, ...)
239 GSList *list, *l;
240 PurpleBuddy *buddy;
241 PurplePresence *presence;
242 PurpleStatus *status;
243 PurpleStatus *old_status;
244 va_list args;
246 g_return_if_fail(account != NULL);
247 g_return_if_fail(name != NULL);
248 g_return_if_fail(status_id != NULL);
249 g_return_if_fail(purple_account_is_connected(account) || purple_account_is_connecting(account));
251 if((list = purple_find_buddies(account, name)) == NULL)
252 return;
254 for(l = list; l != NULL; l = l->next) {
255 buddy = l->data;
257 presence = purple_buddy_get_presence(buddy);
258 status = purple_presence_get_status(presence, status_id);
260 if(NULL == status)
261 continue;
263 old_status = purple_presence_get_active_status(presence);
265 va_start(args, status_id);
266 purple_status_set_active_with_attrs(status, TRUE, args);
267 va_end(args);
269 purple_blist_update_buddy_status(buddy, old_status);
272 g_slist_free(list);
274 /* we get to re-use the last status we found */
275 if (!purple_status_is_online(status))
276 serv_got_typing_stopped(purple_account_get_connection(account), name);
279 void purple_prpl_got_user_status_deactive(PurpleAccount *account, const char *name,
280 const char *status_id)
282 GSList *list, *l;
283 PurpleBuddy *buddy;
284 PurplePresence *presence;
285 PurpleStatus *status;
287 g_return_if_fail(account != NULL);
288 g_return_if_fail(name != NULL);
289 g_return_if_fail(status_id != NULL);
290 g_return_if_fail(purple_account_is_connected(account) || purple_account_is_connecting(account));
292 if((list = purple_find_buddies(account, name)) == NULL)
293 return;
295 for(l = list; l != NULL; l = l->next) {
296 buddy = l->data;
298 presence = purple_buddy_get_presence(buddy);
299 status = purple_presence_get_status(presence, status_id);
301 if(NULL == status)
302 continue;
304 if (purple_status_is_active(status)) {
305 purple_status_set_active(status, FALSE);
306 purple_blist_update_buddy_status(buddy, status);
310 g_slist_free(list);
313 static void
314 do_prpl_change_account_status(PurpleAccount *account,
315 PurpleStatus *old_status, PurpleStatus *new_status)
317 PurplePlugin *prpl;
318 PurplePluginProtocolInfo *prpl_info;
320 if (purple_status_is_online(new_status) &&
321 purple_account_is_disconnected(account) &&
322 purple_network_is_available())
324 purple_account_connect(account);
325 return;
328 if (!purple_status_is_online(new_status))
330 if (!purple_account_is_disconnected(account))
331 purple_account_disconnect(account);
332 /* Clear out the unsaved password if we're already disconnected and we switch to offline status */
333 else if (!purple_account_get_remember_password(account))
334 purple_account_set_password(account, NULL);
335 return;
338 if (purple_account_is_connecting(account))
340 * We don't need to call the set_status PRPL function because
341 * the PRPL will take care of setting its status during the
342 * connection process.
344 return;
346 prpl = purple_find_prpl(purple_account_get_protocol_id(account));
348 if (prpl == NULL)
349 return;
351 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
353 if (!purple_account_is_disconnected(account) && prpl_info->set_status != NULL)
355 prpl_info->set_status(account, new_status);
359 void
360 purple_prpl_change_account_status(PurpleAccount *account,
361 PurpleStatus *old_status, PurpleStatus *new_status)
363 g_return_if_fail(account != NULL);
364 g_return_if_fail(new_status != NULL);
365 g_return_if_fail(!purple_status_is_exclusive(new_status) || old_status != NULL);
367 do_prpl_change_account_status(account, old_status, new_status);
369 purple_signal_emit(purple_accounts_get_handle(), "account-status-changed",
370 account, old_status, new_status);
373 GList *
374 purple_prpl_get_statuses(PurpleAccount *account, PurplePresence *presence)
376 GList *statuses = NULL;
377 GList *l;
378 PurpleStatus *status;
380 g_return_val_if_fail(account != NULL, NULL);
381 g_return_val_if_fail(presence != NULL, NULL);
383 for (l = purple_account_get_status_types(account); l != NULL; l = l->next)
385 status = purple_status_new((PurpleStatusType *)l->data, presence);
386 statuses = g_list_prepend(statuses, status);
389 statuses = g_list_reverse(statuses);
391 return statuses;
394 void
395 purple_prpl_send_attention(PurpleConnection *gc, const char *who, guint type_code)
397 PurpleAttentionType *attn;
398 PurpleMessageFlags flags;
399 PurplePlugin *prpl;
400 PurpleConversation *conv;
401 gboolean (*send_attention)(PurpleConnection *, const char *, guint);
402 PurpleBuddy *buddy;
403 const char *alias;
404 gchar *description;
405 time_t mtime;
407 g_return_if_fail(gc != NULL);
408 g_return_if_fail(who != NULL);
410 prpl = purple_find_prpl(purple_account_get_protocol_id(gc->account));
411 send_attention = PURPLE_PLUGIN_PROTOCOL_INFO(prpl)->send_attention;
412 g_return_if_fail(send_attention != NULL);
414 mtime = time(NULL);
416 attn = purple_get_attention_type_from_code(gc->account, type_code);
418 if ((buddy = purple_find_buddy(purple_connection_get_account(gc), who)) != NULL)
419 alias = purple_buddy_get_contact_alias(buddy);
420 else
421 alias = who;
423 if (attn && purple_attention_type_get_outgoing_desc(attn)) {
424 description = g_strdup_printf(purple_attention_type_get_outgoing_desc(attn), alias);
425 } else {
426 description = g_strdup_printf(_("Requesting %s's attention..."), alias);
429 flags = PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_NOTIFY | PURPLE_MESSAGE_SYSTEM;
431 purple_debug_info("server", "serv_send_attention: sending '%s' to %s\n",
432 description, who);
434 if (!send_attention(gc, who, type_code))
435 return;
437 conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, gc->account, who);
438 purple_conv_im_write(PURPLE_CONV_IM(conv), NULL, description, flags, mtime);
440 g_free(description);
443 static void
444 got_attention(PurpleConnection *gc, int id, const char *who, guint type_code)
446 PurpleMessageFlags flags;
447 PurpleAttentionType *attn;
448 PurpleBuddy *buddy;
449 const char *alias;
450 gchar *description;
451 time_t mtime;
453 mtime = time(NULL);
455 attn = purple_get_attention_type_from_code(gc->account, type_code);
457 /* PURPLE_MESSAGE_NOTIFY is for attention messages. */
458 flags = PURPLE_MESSAGE_SYSTEM | PURPLE_MESSAGE_NOTIFY | PURPLE_MESSAGE_RECV;
460 /* TODO: if (attn->icon_name) is non-null, use it to lookup an emoticon and display
461 * it next to the attention command. And if it is null, display a generic icon. */
463 if ((buddy = purple_find_buddy(purple_connection_get_account(gc), who)) != NULL)
464 alias = purple_buddy_get_contact_alias(buddy);
465 else
466 alias = who;
468 if (attn && purple_attention_type_get_incoming_desc(attn)) {
469 description = g_strdup_printf(purple_attention_type_get_incoming_desc(attn), alias);
470 } else {
471 description = g_strdup_printf(_("%s has requested your attention!"), alias);
474 purple_debug_info("server", "got_attention: got '%s' from %s\n",
475 description, who);
477 if (id == -1)
478 serv_got_im(gc, who, description, flags, mtime);
479 else
480 serv_got_chat_in(gc, id, who, flags, description, mtime);
482 /* TODO: sounds (depending on PurpleAttentionType), shaking, etc. */
484 g_free(description);
487 void
488 purple_prpl_got_attention(PurpleConnection *gc, const char *who, guint type_code)
490 got_attention(gc, -1, who, type_code);
493 void
494 purple_prpl_got_attention_in_chat(PurpleConnection *gc, int id, const char *who, guint type_code)
496 got_attention(gc, id, who, type_code);
499 /**************************************************************************
500 * Protocol Plugin Subsystem API
501 **************************************************************************/
503 PurplePlugin *
504 purple_find_prpl(const char *id)
506 GList *l;
507 PurplePlugin *plugin;
509 g_return_val_if_fail(id != NULL, NULL);
511 for (l = purple_plugins_get_protocols(); l != NULL; l = l->next) {
512 plugin = (PurplePlugin *)l->data;
514 if (!strcmp(plugin->info->id, id))
515 return plugin;
518 return NULL;