Instead of spamming, do everything ridiculously slowly.
[thrasher.git] / thblist.c
blob82d469f934671fb611bbea1a74941c50e1e95a49
1 /*
2 * Thrasher Bird - XMPP transport via libpurple
3 * Copyright (C) 2008 Barracuda Networks, Inc.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Thrasher Bird; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
19 #include <stdlib.h>
20 #include "blist.h"
21 #include "thperl.h"
22 #include "thrasher.h"
23 #include "thblist.h"
24 #include "status.h"
26 #include <server.h>
27 #include <account.h>
29 void thrasher_buddy_status_changed (PurpleBuddy *buddy, PurpleStatus *old,
30 PurpleStatus *new);
31 void thrasher_buddy_signed_on (PurpleBuddy *buddy);
32 void thrasher_buddy_signed_off (PurpleBuddy *buddy);
33 void thrasher_buddy_added (PurpleBuddy *buddy);
34 void thrasher_buddy_add_request (PurpleAccount *account, const char *remote_user,
35 const char *id, const char *alias,
36 const char *message);
37 static void * thrasher_buddy_request_authorize
38 (PurpleAccount *account,
39 const char *remote_user,
40 const char *id,
41 const char *alias,
42 const char *message,
43 gboolean on_list,
44 PurpleAccountRequestAuthorizationCb authorize_cb,
45 PurpleAccountRequestAuthorizationCb deny_cb,
46 void *user_data);
47 void thrasher_buddy_removed (PurpleBuddy *buddy);
48 static gpointer thrasher_blist_get_handle (void);
49 static char* status_text_for_buddy(PurpleBuddy *buddy, PurpleStatus *status);
51 static gboolean thrasher_buddy_request_authorize_cb1(gpointer data_in);
52 static gboolean thrasher_buddy_request_authorize_cb2(gpointer data_in);
55 static PurpleAccountUiOps thrasher_account_uiops =
57 // notify added
58 thrasher_buddy_add_request,
60 // status changed
61 NULL,
63 // request add
64 thrasher_buddy_add_request,
66 // request_authorize
67 thrasher_buddy_request_authorize,
69 // close_account_request
70 NULL,
71 // save_node
72 NULL,
73 // remove_node
74 NULL,
75 // save_account
76 NULL,
77 // Reserved
78 NULL
81 struct _PurpleStatusType
83 PurpleStatusPrimitive primitive;
85 char *id;
86 char *name;
87 char *primary_attr_id;
89 gboolean saveable;
90 gboolean user_settable;
91 gboolean independent;
93 GList *attrs;
97 struct _PurpleStatus
99 struct _PurpleStatusType *type;
100 PurplePresence *presence;
102 const char *title;
104 gboolean active;
106 GHashTable *attr_values;
110 * @brief This is the callback for the buddy-status-changed signal
111 * @param buddy PurpleBuddy struct
112 * @param old (unused)
113 * @param new @buddy new PurpleStatus
115 void thrasher_buddy_status_changed (PurpleBuddy *buddy,
116 PurpleStatus *old,
117 PurpleStatus *new)
119 PurpleGroup *group;
120 const char *group_name = NULL;
121 const char *alias = NULL;
123 g_return_if_fail(buddy != NULL);
124 g_return_if_fail(new != NULL);
126 group = purple_buddy_get_group(buddy);
128 if (group)
129 group_name = purple_group_get_name(group);
131 alias = purple_buddy_get_alias_only(buddy);
133 char* message = status_text_for_buddy(buddy, new);
134 if (! message) {
135 message = g_strdup(purple_status_get_attr_string(new, "message"));
138 thrasher_wrapper_presence_in(thrasher_account_get_jid(buddy->account),
139 purple_buddy_get_name(buddy),
140 alias,
141 group_name,
142 purple_status_type_get_primitive(new->type),
143 message);
144 g_free(message);
147 /* Returns a string that becomes owned by the caller or NULL. */
148 static char*
149 status_text_for_buddy(PurpleBuddy *buddy,
150 PurpleStatus *status) {
151 if (! buddy) {
152 return NULL;
154 if (! buddy->account->gc) {
155 return NULL;
158 const char *prpl_id = purple_account_get_protocol_id(buddy->account);
159 if (prpl_id) {
160 PurplePlugin *prpl = purple_find_prpl(prpl_id);
161 if (prpl) {
162 PurplePluginProtocolInfo *prpl_info
163 = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
164 if (prpl_info && prpl_info->status_text) {
165 char* status_text = prpl_info->status_text(buddy);
166 if (status && status_text
167 && purple_status_is_available(status)
168 && 0 == strcmp(prpl_id, "prpl-icq")
169 && 0 == strcmp(status_text,
170 purple_status_get_name(status))) {
171 /* The oscar prpl's status_text tries to suppress
172 * a redundant "Available" message, but won't if
173 * it's in the message attribute instead of the
174 * status name. libpurple's initial log on does
175 * not set this in the message, but subsequent
176 * status changes will.
178 status_text = g_strdup("");
180 return status_text;
184 return NULL;
186 void thrasher_buddy_authorize (const char *jid,
187 const char *legacy_username) {
188 g_return_if_fail(jid);
189 g_return_if_fail(legacy_username);
191 PurpleAccount *account = thrasher_get_account_by_jid(jid);
192 g_return_if_fail(account);
194 PurpleConnection *gc =
195 thrasher_get_connection_by_account(account);
196 g_return_if_fail(gc);
198 purple_debug_info("thrasher", "Authorizing %s for jid %s (%s)\n",
199 legacy_username, jid,
200 purple_account_get_username(account));
202 // defensive; probably only add_permit is necesary
203 serv_rem_deny(gc, legacy_username);
205 serv_add_permit(gc, legacy_username);
208 void thrasher_buddy_deauthorize (const char *jid,
209 const char *legacy_username) {
210 g_return_if_fail(jid);
211 g_return_if_fail(legacy_username);
213 PurpleAccount *account = thrasher_get_account_by_jid(jid);
214 g_return_if_fail(account);
216 PurpleConnection *gc =
217 thrasher_get_connection_by_account(account);
218 g_return_if_fail(gc);
220 purple_debug_info("thrasher", "Deauthorizing %s for jid %s\n",
221 legacy_username, jid);
223 // no corresponding deny, we don't have a reperesentation for that
224 serv_rem_permit(gc, legacy_username);
227 void thrasher_buddy_signed_on (PurpleBuddy *buddy)
229 PurplePresence *presence;
231 presence = purple_buddy_get_presence(buddy);
233 if (!presence)
234 return;
236 // libpurple uses this to populate some stuff about the
237 // buddy, particularly useful for XMPP file transfers but
238 // probably the cause of random other errors if we don't fill this
239 // out.
240 PurpleAccount* account = buddy->account;
241 g_return_if_fail(account);
242 PurpleConnection* connection = thrasher_connection_for_account(account);
243 g_return_if_fail(connection);
245 purple_debug_info("thblist",
246 "getting server info for %s\n\n---------\n\n",
247 buddy->name);
248 serv_get_info(connection, buddy->name);
250 /* Currently active status may be PURPLE_STATUS_UNAVAILABLE
251 * (translates XMPP dnd) instead of just "available".
253 PurpleStatus *status = purple_presence_get_active_status(presence);
255 thrasher_buddy_status_changed(buddy,
256 NULL,
257 status);
260 void thrasher_buddy_signed_off (PurpleBuddy *buddy)
262 PurplePresence *presence;
264 presence = purple_buddy_get_presence(buddy);
266 if (!presence)
267 return;
269 thrasher_buddy_status_changed(buddy,
270 NULL,
271 purple_presence_get_status(presence, "offline"));
274 struct auth_request_cb_data {
275 PurpleAccount *account;
276 char *remote_user;
277 char *alias;
278 char *message;
279 PurpleAccountRequestAuthorizationCb authorize_cb;
280 void *user_data;
283 static void * thrasher_buddy_request_authorize
284 (PurpleAccount *account,
285 const char *remote_user,
286 const char *id,
287 const char *alias,
288 const char *message,
289 gboolean on_list,
290 PurpleAccountRequestAuthorizationCb authorize_cb,
291 PurpleAccountRequestAuthorizationCb deny_cb,
292 void *user_data) {
293 purple_debug_info("thrasher", "%s request_authorize from %s reached cb0\n",
294 remote_user,
295 thrasher_account_get_jid(account));
297 struct auth_request_cb_data *data
298 = g_malloc(sizeof(struct auth_request_cb_data));
299 data->account = account;
300 data->remote_user = g_strdup(remote_user);
301 data->alias = g_strdup(alias);
302 data->message = g_strdup(message);
303 data->authorize_cb = authorize_cb;
304 data->user_data = user_data;
305 purple_timeout_add_seconds(2,
306 thrasher_buddy_request_authorize_cb1,
307 data);
309 void *uihandle = NULL;
310 return uihandle;
313 static gboolean
314 thrasher_buddy_request_authorize_cb1(gpointer data_in) {
315 struct auth_request_cb_data *data = data_in;
316 purple_debug_info("thrasher", "%s request_authorize from %s reached cb1\n",
317 data->remote_user,
318 thrasher_account_get_jid(data->account));
319 if (data->authorize_cb) {
320 data->authorize_cb(data->user_data);
322 else {
323 /* FIXME: I don't think this actually happens? Any more? */
324 purple_debug_info("thrasher", "authorize_cb sometimes NULL?!?\n");
326 purple_timeout_add_seconds(2,
327 thrasher_buddy_request_authorize_cb2,
328 data);
329 return FALSE;
332 static gboolean
333 thrasher_buddy_request_authorize_cb2(gpointer data_in) {
334 struct auth_request_cb_data *data = data_in;
335 purple_debug_info("thrasher", "%s request_authorize from %s reached cb2\n",
336 data->remote_user,
337 thrasher_account_get_jid(data->account));
338 /* FIXME: call through purple_blist_request_add_buddy() and blist ui_ops. */
339 thrasher_buddy_add_request(data->account,
340 data->remote_user,
342 data->alias,
343 data->message);
344 g_free(data->remote_user);
345 g_free(data->alias);
346 g_free(data->message);
347 g_free(data);
348 return FALSE;
351 /* thrasher_buddy_add_request
353 * Triggered on a buddy-added signal, this allows us to push new subscriptions.
356 void thrasher_buddy_added (PurpleBuddy *buddy) {
357 PurplePresence *presence = purple_buddy_get_presence(buddy);
358 PurpleStatus *status = purple_presence_get_active_status(presence);
359 PurpleStatusType *type = purple_status_get_type(status);
361 const char *jid = thrasher_account_get_jid(buddy->account);
362 const char *sender = purple_buddy_get_name(buddy);
363 const guint status_int = purple_status_type_get_primitive(type);
365 purple_debug_info("thrasher",
366 "buddy added to %s: %s\n",
367 jid, sender);
369 thrasher_wrapper_subscription_add(jid, sender, status_int);
373 void thrasher_buddy_add_request (PurpleAccount *account, const char *remote_user,
374 const char *id, const char *alias,
375 const char *message)
377 const char *jid = thrasher_account_get_jid(account);
378 if (! alias) {
379 alias = "(unknown)";
381 purple_debug_info("thrasher",
382 "legacy user %s aka %s added %s to roster\n",
383 remote_user, alias, jid);
384 thrasher_wrapper_legacy_user_add_user(jid, remote_user);
388 void thrasher_buddy_removed (PurpleBuddy *buddy)
390 /* printf("Removed buddy:\t[%s]\t[%s]\n", purple_buddy_get_name(buddy),
391 * purple_status_get_name( purple_presence_get_active_status( purple_buddy_get_presence(buddy) ) )
392 * );
394 PurplePresence *presence = purple_buddy_get_presence(buddy);
395 PurpleStatus *status = purple_presence_get_active_status(presence);
396 PurpleStatusType *type = purple_status_get_type(status);
397 PurpleGroup *group = purple_buddy_get_group(buddy);
399 * Need to fire jid, sender, group_name, alias, and status back to perl */
401 // jid = thrasher_account_get_jid(buddy->account)
402 // sender = purple_buddy_get_name(buddy)
403 // group_name = purple_group_get_name(group)
404 // alias = purple_buddy_get_alias_only(buddy)
405 // status = purple_status_type_get_primitive(type)
409 static gpointer
410 thrasher_blist_get_handle ()
412 static int handle;
413 return &handle;
417 void thrasher_blist_init()
419 purple_accounts_set_ui_ops(&thrasher_account_uiops);
421 purple_signal_connect(purple_blist_get_handle(),
422 "buddy-status-changed",
423 thrasher_blist_get_handle(),
424 PURPLE_CALLBACK(thrasher_buddy_status_changed),
425 NULL);
427 purple_signal_connect(purple_blist_get_handle(),
428 "buddy-signed-on",
429 thrasher_blist_get_handle(),
430 PURPLE_CALLBACK(thrasher_buddy_signed_on),
431 NULL);
433 purple_signal_connect(purple_blist_get_handle(),
434 "buddy-signed-off",
435 thrasher_blist_get_handle(),
436 PURPLE_CALLBACK(thrasher_buddy_signed_off),
437 NULL);
439 // It looks like this only comes in for things already on our roster.
440 purple_signal_connect(purple_blist_get_handle(),
441 "buddy-added",
442 thrasher_blist_get_handle(),
443 PURPLE_CALLBACK(thrasher_buddy_added),
444 NULL);
447 purple_signal_connect(purple_blist_get_handle(),
448 "buddy-removed",
449 thrasher_blist_get_handle(),
450 PURPLE_CALLBACK(thrasher_buddy_removed),
451 NULL);