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
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
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
);
76 static gchar
* ggp_status_validate_description(const gchar
* msg
)
78 if (msg
== NULL
|| msg
[0] == '\0')
81 return ggp_utf8_strndup(msg
, GG_STATUS_DESCR_MAXSIZE
);
84 GList
* ggp_status_types(PurpleAccount
*account
)
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
));
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);
130 if (status_message
) {
131 gchar
*stripped
= purple_markup_strip_html(status_message
);
132 g_strstrip(stripped
);
133 *message
= ggp_status_validate_description(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
)
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
);
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
);
175 case GG_STATUS_BUSY_DESCR
:
176 return purple_primitive_get_id_from_type(
178 case GG_STATUS_INVISIBLE
:
179 case GG_STATUS_INVISIBLE_DESCR
:
180 return purple_primitive_get_id_from_type(
181 PURPLE_STATUS_INVISIBLE
);
183 case GG_STATUS_DND_DESCR
:
184 return purple_primitive_get_id_from_type(
185 PURPLE_STATUS_UNAVAILABLE
);
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)
197 return purple_primitive_get_name_from_type(
198 purple_primitive_get_type_from_id(purple_status
));
201 /*******************************************************************************
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
);
241 g_free(ssdata
->current_description
);
242 ssdata
->current_description
= new_description
;
245 gg_change_status(accdata
->session
, status
);
247 gg_change_status_descr(accdata
->session
, status
, new_description
);
252 void ggp_status_set_purplestatus(PurpleAccount
*account
, PurpleStatus
*status
)
257 if (!purple_status_is_active(status
))
260 status_gg
= ggp_status_from_purplestatus(status
, &msg
);
261 ggp_status_set(account
, status_gg
, msg
);
265 void ggp_status_set_disconnected(PurpleAccount
*account
)
269 ggp_status_from_purplestatus(purple_account_get_active_status(account
),
271 if (!ggp_status_set(account
,
272 msg
? GG_STATUS_NOT_AVAIL_DESCR
: GG_STATUS_NOT_AVAIL
, msg
))
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)
286 now = ggp_microtime();
287 if (now - wait_start + sleep_time >= 100000)
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
,
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"),
357 _("OK"), G_CALLBACK(ggp_status_broadcasting_dialog_ok
),
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 /*******************************************************************************
371 ******************************************************************************/
373 void ggp_status_got_others_buddy(PurpleConnection
*gc
, uin_t uin
, int status
,
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
;
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
);
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
,
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
;
404 is_own
= (!g_strcmp0(ggp_uin_to_str(uin
),
405 purple_account_get_username(account
)));
409 purple_debug_warning("gg",
410 "ggp_status_got_others_buddy: "
411 "buddy %u not found\n", uin
);
415 ggp_buddy_get_data(buddy
)->blocked
= (status
== GG_STATUS_BLOCKED
);
416 ggp_buddy_get_data(buddy
)->not_a_friend
= (status
== GG_STATUS_UNKNOWN
);
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
);
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");
464 return g_markup_escape_text(purple_message
, -1);