Replace functions which called once with their bodies
[pidgin-git.git] / libpurple / protocols / gg / status.c
blobbd993cc8719158bb6719764ffddaecc0b8100c63
1 /* purple
3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
5 * source distribution.
7 * Rewritten from scratch during Google Summer of Code 2012
8 * by Tomek Wasilczyk (http://www.wasilczyk.pl).
10 * Previously implemented by:
11 * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
12 * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
13 * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
30 #include "status.h"
32 #include <libgadu.h>
33 #include <debug.h>
34 #include <request.h>
36 #include "gg.h"
37 #include "utils.h"
39 struct _ggp_status_session_data
41 gboolean status_broadcasting;
42 gchar *current_description;
45 static inline ggp_status_session_data *
46 ggp_status_get_ssdata(PurpleConnection *gc);
48 static gchar * ggp_status_validate_description(const gchar* msg);
50 static inline ggp_status_session_data *
51 ggp_status_get_ssdata(PurpleConnection *gc)
53 GGPInfo *accdata = purple_connection_get_protocol_data(gc);
54 return accdata->status_data;
57 void ggp_status_setup(PurpleConnection *gc)
59 GGPInfo *accdata = purple_connection_get_protocol_data(gc);
60 PurpleAccount *account = purple_connection_get_account(gc);
62 ggp_status_session_data *ssdata = g_new0(ggp_status_session_data, 1);
63 accdata->status_data = ssdata;
65 ssdata->status_broadcasting =
66 purple_account_get_bool(account, "status_broadcasting", TRUE);
69 void ggp_status_cleanup(PurpleConnection *gc)
71 ggp_status_session_data *ssdata = ggp_status_get_ssdata(gc);
72 g_free(ssdata->current_description);
73 g_free(ssdata);
76 static gchar * ggp_status_validate_description(const gchar* msg)
78 if (msg == NULL || msg[0] == '\0')
79 return NULL;
81 return ggp_utf8_strndup(msg, GG_STATUS_DESCR_MAXSIZE);
84 GList * ggp_status_types(PurpleAccount *account)
86 GList *types = NULL;
88 types = g_list_append(types, purple_status_type_new_with_attrs(
89 PURPLE_STATUS_AVAILABLE, NULL, NULL,
90 TRUE, TRUE, FALSE, "message", _("Message"),
91 purple_value_new(G_TYPE_STRING), NULL));
93 types = g_list_append(types, purple_status_type_new_with_attrs(
94 PURPLE_STATUS_AVAILABLE, "freeforchat", _("Chatty"),
95 TRUE, TRUE, FALSE, "message", _("Message"),
96 purple_value_new(G_TYPE_STRING), NULL));
98 types = g_list_append(types, purple_status_type_new_with_attrs(
99 PURPLE_STATUS_AWAY, NULL, NULL,
100 TRUE, TRUE, FALSE, "message", _("Message"),
101 purple_value_new(G_TYPE_STRING), NULL));
103 types = g_list_append(types, purple_status_type_new_with_attrs(
104 PURPLE_STATUS_UNAVAILABLE, NULL, NULL,
105 TRUE, TRUE, FALSE, "message", _("Message"),
106 purple_value_new(G_TYPE_STRING), NULL));
108 types = g_list_append(types, purple_status_type_new_with_attrs(
109 PURPLE_STATUS_INVISIBLE, NULL, NULL,
110 TRUE, TRUE, FALSE, "message", _("Message"),
111 purple_value_new(G_TYPE_STRING), NULL));
113 types = g_list_append(types, purple_status_type_new_with_attrs(
114 PURPLE_STATUS_OFFLINE, NULL, NULL,
115 TRUE, TRUE, FALSE, "message", _("Message"),
116 purple_value_new(G_TYPE_STRING), NULL));
118 return types;
121 int ggp_status_from_purplestatus(PurpleStatus *status, gchar **message)
123 const char *status_id = purple_status_get_id(status);
124 const char *status_message =
125 purple_status_get_attr_string(status, "message");
127 g_return_val_if_fail(message != NULL, 0);
129 *message = NULL;
130 if (status_message) {
131 gchar *stripped = purple_markup_strip_html(status_message);
132 g_strstrip(stripped);
133 *message = ggp_status_validate_description(stripped);
134 g_free(stripped);
137 if (0 == strcmp(status_id, "available"))
138 return status_message ? GG_STATUS_AVAIL_DESCR : GG_STATUS_AVAIL;
139 if (0 == strcmp(status_id, "freeforchat"))
140 return status_message ? GG_STATUS_FFC_DESCR : GG_STATUS_FFC;
141 if (0 == strcmp(status_id, "away"))
142 return status_message ? GG_STATUS_BUSY_DESCR : GG_STATUS_BUSY;
143 if (0 == strcmp(status_id, "unavailable"))
144 return status_message ? GG_STATUS_DND_DESCR : GG_STATUS_DND;
145 if (0 == strcmp(status_id, "invisible"))
146 return status_message ?
147 GG_STATUS_INVISIBLE_DESCR : GG_STATUS_INVISIBLE;
148 if (0 == strcmp(status_id, "offline"))
149 return status_message ?
150 GG_STATUS_NOT_AVAIL_DESCR : GG_STATUS_NOT_AVAIL;
152 purple_debug_error("gg", "ggp_status_from_purplestatus: "
153 "unknown status requested (%s)\n", status_id);
154 return status_message ? GG_STATUS_AVAIL_DESCR : GG_STATUS_AVAIL;
157 const gchar * ggp_status_to_purplestatus(int status)
159 switch (status)
161 case GG_STATUS_NOT_AVAIL:
162 case GG_STATUS_NOT_AVAIL_DESCR:
163 case GG_STATUS_BLOCKED:
164 case GG_STATUS_UNKNOWN:
165 return purple_primitive_get_id_from_type(
166 PURPLE_STATUS_OFFLINE);
167 case GG_STATUS_FFC:
168 case GG_STATUS_FFC_DESCR:
169 return "freeforchat";
170 case GG_STATUS_AVAIL:
171 case GG_STATUS_AVAIL_DESCR:
172 return purple_primitive_get_id_from_type(
173 PURPLE_STATUS_AVAILABLE);
174 case GG_STATUS_BUSY:
175 case GG_STATUS_BUSY_DESCR:
176 return purple_primitive_get_id_from_type(
177 PURPLE_STATUS_AWAY);
178 case GG_STATUS_INVISIBLE:
179 case GG_STATUS_INVISIBLE_DESCR:
180 return purple_primitive_get_id_from_type(
181 PURPLE_STATUS_INVISIBLE);
182 case GG_STATUS_DND:
183 case GG_STATUS_DND_DESCR:
184 return purple_primitive_get_id_from_type(
185 PURPLE_STATUS_UNAVAILABLE);
186 default:
187 purple_debug_warning("gg", "ggp_status_to_purplestatus: unknown status %#02x\n", status);
188 return purple_primitive_get_id_from_type(
189 PURPLE_STATUS_AVAILABLE);
193 const gchar * ggp_status_get_name(const gchar *purple_status)
195 if (g_strcmp0(purple_status, "freeforchat") == 0)
196 return _("Chatty");
197 return purple_primitive_get_name_from_type(
198 purple_primitive_get_type_from_id(purple_status));
201 /*******************************************************************************
202 * Own status.
203 ******************************************************************************/
205 static void ggp_status_broadcasting_dialog_ok(PurpleConnection *gc,
206 PurpleRequestFields *fields);
208 /******************************************************************************/
210 void ggp_status_set_initial(PurpleConnection *gc, struct gg_login_params *glp)
212 ggp_status_session_data *ssdata = ggp_status_get_ssdata(gc);
213 PurpleAccount *account = purple_connection_get_account(gc);
215 glp->status = ggp_status_from_purplestatus(
216 purple_account_get_active_status(account), &glp->status_descr);
217 if (!ggp_status_get_status_broadcasting(gc))
218 glp->status |= GG_STATUS_FRIENDS_MASK;
219 ssdata->current_description = g_strdup(glp->status_descr);
222 gboolean ggp_status_set(PurpleAccount *account, int status, const gchar* msg)
224 PurpleConnection *gc = purple_account_get_connection(account);
225 ggp_status_session_data *ssdata = ggp_status_get_ssdata(gc);
226 GGPInfo *accdata = purple_connection_get_protocol_data(gc);
227 gchar *new_description = ggp_status_validate_description(msg);
229 if (!ssdata->status_broadcasting)
230 status |= GG_STATUS_FRIENDS_MASK;
232 if ((status == GG_STATUS_NOT_AVAIL ||
233 status == GG_STATUS_NOT_AVAIL_DESCR) &&
234 0 == g_strcmp0(ssdata->current_description, new_description))
236 purple_debug_info("gg", "ggp_status_set: new status doesn't "
237 "differ when closing connection - ignore\n");
238 g_free(new_description);
239 return FALSE;
241 g_free(ssdata->current_description);
242 ssdata->current_description = new_description;
244 if (msg == NULL)
245 gg_change_status(accdata->session, status);
246 else
247 gg_change_status_descr(accdata->session, status, new_description);
249 return TRUE;
252 void ggp_status_set_purplestatus(PurpleAccount *account, PurpleStatus *status)
254 int status_gg;
255 gchar *msg = NULL;
257 if (!purple_status_is_active(status))
258 return;
260 status_gg = ggp_status_from_purplestatus(status, &msg);
261 ggp_status_set(account, status_gg, msg);
262 g_free(msg);
265 void ggp_status_set_disconnected(PurpleAccount *account)
267 gchar *msg = NULL;
269 ggp_status_from_purplestatus(purple_account_get_active_status(account),
270 &msg);
271 if (!ggp_status_set(account,
272 msg ? GG_STATUS_NOT_AVAIL_DESCR : GG_STATUS_NOT_AVAIL, msg))
274 g_free(msg);
275 return;
279 struct gg_event *ev;
280 guint64 wait_start = ggp_microtime(), now;
281 int sleep_time = 5000;
282 while ((ev = gg_watch_fd(info->session)) != NULL)
284 if (ev->type == GG_EVENT_DISCONNECT_ACK)
285 break;
286 now = ggp_microtime();
287 if (now - wait_start + sleep_time >= 100000)
288 break;
289 usleep(sleep_time);
290 sleep_time *= 2;
293 g_usleep(100000);
295 g_free(msg);
298 void ggp_status_fake_to_self(PurpleConnection *gc)
300 PurpleAccount *account = purple_connection_get_account(gc);
301 PurpleStatus *status = purple_presence_get_active_status(
302 purple_account_get_presence(account));
303 const char *status_msg = purple_status_get_attr_string(status,
304 "message");
305 gchar *status_msg_gg = NULL;
307 if (status_msg != NULL && status_msg[0] != '\0') {
308 status_msg_gg = g_new0(gchar, GG_STATUS_DESCR_MAXSIZE + 1);
309 g_utf8_strncpy(status_msg_gg, status_msg,
310 GG_STATUS_DESCR_MAXSIZE);
313 purple_protocol_got_user_status(account,
314 purple_account_get_username(account),
315 purple_status_get_id(status),
316 status_msg_gg ? "message" : NULL, status_msg_gg, NULL);
318 g_free(status_msg_gg);
321 gboolean ggp_status_get_status_broadcasting(PurpleConnection *gc)
323 return ggp_status_get_ssdata(gc)->status_broadcasting;
326 void ggp_status_set_status_broadcasting(PurpleConnection *gc,
327 gboolean broadcasting)
329 PurpleAccount *account = purple_connection_get_account(gc);
331 ggp_status_get_ssdata(gc)->status_broadcasting = broadcasting;
332 purple_account_set_bool(account, "status_broadcasting", broadcasting);
333 ggp_status_set_purplestatus(account,
334 purple_account_get_active_status(account));
337 void ggp_status_broadcasting_dialog(PurpleConnection *gc)
339 PurpleRequestFields *fields;
340 PurpleRequestFieldGroup *group;
341 PurpleRequestField *field;
343 fields = purple_request_fields_new();
344 group = purple_request_field_group_new(NULL);
345 purple_request_fields_add_group(fields, group);
347 field = purple_request_field_bool_new("buddies_only",
348 _("Show status only for buddies"),
349 !ggp_status_get_status_broadcasting(gc));
350 purple_request_field_group_add_field(group, field);
352 purple_request_fields(gc,
353 _("Change status broadcasting"),
354 _("Please, select who can see your status"),
355 NULL,
356 fields,
357 _("OK"), G_CALLBACK(ggp_status_broadcasting_dialog_ok),
358 _("Cancel"), NULL,
359 purple_request_cpar_from_connection(gc), gc);
362 static void ggp_status_broadcasting_dialog_ok(PurpleConnection *gc,
363 PurpleRequestFields *fields)
365 ggp_status_set_status_broadcasting(gc,
366 !purple_request_fields_get_bool(fields, "buddies_only"));
369 /*******************************************************************************
370 * Buddy status.
371 ******************************************************************************/
373 void ggp_status_got_others_buddy(PurpleConnection *gc, uin_t uin, int status,
374 const char *descr);
376 /******************************************************************************/
378 void ggp_status_got_others(PurpleConnection *gc, struct gg_event *ev)
380 if (ev->type == GG_EVENT_NOTIFY60) {
381 struct gg_event_notify60 *notify = ev->event.notify60;
382 int i;
383 for (i = 0; notify[i].uin; i++)
384 ggp_status_got_others_buddy(gc, notify[i].uin,
385 GG_S(notify[i].status), notify[i].descr);
386 } else if (ev->type == GG_EVENT_STATUS60) {
387 struct gg_event_status60 *notify = &ev->event.status60;
388 ggp_status_got_others_buddy(gc, notify->uin,
389 GG_S(notify->status), notify->descr);
390 } else
391 purple_debug_fatal("gg", "ggp_status_got_others: "
392 "unexpected event %d\n", ev->type);
395 void ggp_status_got_others_buddy(PurpleConnection *gc, uin_t uin, int status,
396 const char *descr)
398 PurpleAccount *account = purple_connection_get_account(gc);
399 PurpleBuddy *buddy = purple_blist_find_buddy(account, ggp_uin_to_str(uin));
400 const gchar *purple_status = ggp_status_to_purplestatus(status);
401 gchar *status_message = NULL;
402 gboolean is_own;
404 is_own = (!g_strcmp0(ggp_uin_to_str(uin),
405 purple_account_get_username(account)));
407 if (!buddy) {
408 if (!is_own) {
409 purple_debug_warning("gg",
410 "ggp_status_got_others_buddy: "
411 "buddy %u not found\n", uin);
413 return;
415 ggp_buddy_get_data(buddy)->blocked = (status == GG_STATUS_BLOCKED);
416 ggp_buddy_get_data(buddy)->not_a_friend = (status == GG_STATUS_UNKNOWN);
418 if (descr != NULL) {
419 status_message = g_strdup(descr);
420 g_strstrip(status_message);
421 if (status_message[0] == '\0') {
422 g_free(status_message);
423 status_message = NULL;
427 if (uin == ggp_str_to_uin(purple_account_get_username(account))) {
428 purple_debug_info("gg", "ggp_status_got_others_buddy: "
429 "own status changed to %s [%s]\n",
430 purple_status, status_message ? status_message : "");
431 } else if (purple_debug_is_verbose()) {
432 purple_debug_misc("gg", "ggp_status_got_others_buddy: "
433 "status of %u changed to %s [%s]\n", uin,
434 purple_status, status_message ? status_message : "");
437 if (status_message) {
438 purple_protocol_got_user_status(account, ggp_uin_to_str(uin),
439 purple_status, "message", status_message, NULL);
440 } else {
441 purple_protocol_got_user_status(account, ggp_uin_to_str(uin),
442 purple_status, NULL);
445 g_free(status_message);
448 char * ggp_status_buddy_text(PurpleBuddy *buddy)
450 ggp_buddy_data *buddy_data = ggp_buddy_get_data(buddy);
451 const gchar *purple_message;
453 if (buddy_data->blocked)
454 return g_strdup(_("Blocked"));
455 if (buddy_data->not_a_friend)
456 return g_strdup(_("Not a buddy"));
458 purple_message = purple_status_get_attr_string(
459 purple_presence_get_active_status(
460 purple_buddy_get_presence(buddy)), "message");
461 if (!purple_message)
462 return NULL;
464 return g_markup_escape_text(purple_message, -1);