Replace functions which called once with their bodies
[pidgin-git.git] / libpurple / protocols / novell / novell.c
blobe4959fd3e27dbab8fdfbadbb29c8c3530ffd5df8
1 /*
2 * novell.c
4 * Copyright (c) 2004 Novell, Inc. All Rights Reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
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 this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
21 #include "internal.h"
23 #include "action.h"
24 #include "debug.h"
25 #include "plugins.h"
26 #include "server.h"
27 #include "nmuser.h"
28 #include "notify.h"
29 #include "novell.h"
30 #include "purpleaccountoption.h"
31 #include "util.h"
32 #include "sslconn.h"
33 #include "request.h"
34 #include "network.h"
35 #include "status.h"
36 #include "version.h"
38 #define DEFAULT_PORT 8300
39 #define NOVELL_CONNECT_STEPS 4
40 #define NM_ROOT_FOLDER_NAME "GroupWise Messenger"
42 #define NOVELL_STATUS_TYPE_AVAILABLE "available"
43 #define NOVELL_STATUS_TYPE_AWAY "away"
44 #define NOVELL_STATUS_TYPE_BUSY "busy"
45 #define NOVELL_STATUS_TYPE_OFFLINE "offline"
46 #define NOVELL_STATUS_TYPE_IDLE "idle"
47 #define NOVELL_STATUS_TYPE_APPEAR_OFFLINE "appearoffline"
49 static PurpleProtocol *my_protocol = NULL;
51 static gboolean
52 _is_disconnect_error(NMERR_T err);
54 static gboolean
55 _check_for_disconnect(NMUser * user, NMERR_T err);
57 static void
58 _send_message(NMUser * user, NMMessage * message);
60 static void
61 _update_buddy_status(NMUser *user, PurpleBuddy * buddy, int status, int gmt);
63 static void
64 _remove_purple_buddies(NMUser * user);
66 static void
67 _add_contacts_to_purple_blist(NMUser * user, NMFolder * folder);
69 static void
70 _add_purple_buddies(NMUser * user);
72 static void
73 _sync_contact_list(NMUser *user);
75 static void
76 _sync_privacy_lists(NMUser *user);
78 static void
79 _show_info(PurpleConnection * gc, NMUserRecord * user_record, char * name);
81 const char *
82 _get_conference_name(int id);
84 /*******************************************************************************
85 * Response callbacks
86 *******************************************************************************/
88 /* Handle login response */
89 static void
90 _login_resp_cb(NMUser * user, NMERR_T ret_code,
91 gpointer resp_data, gpointer user_data)
93 PurpleConnection *gc;
94 const char *alias;
95 NMERR_T rc;
97 if (user == NULL)
98 return;
100 gc = purple_account_get_connection(user->client_data);
101 if (gc == NULL)
102 return;
104 if (ret_code == NM_OK) {
106 /* Set alias for user if not set (use Full Name) */
107 alias = purple_account_get_private_alias(user->client_data);
108 if (alias == NULL || *alias == '\0') {
109 alias = nm_user_record_get_full_name(user->user_record);
111 if (alias)
112 purple_account_set_private_alias(user->client_data, alias);
115 /* Tell Purple that we are connected */
116 purple_connection_set_state(gc, PURPLE_CONNECTION_CONNECTED);
118 _sync_contact_list(user);
120 rc = nm_send_set_status(user, NM_STATUS_AVAILABLE, NULL, NULL, NULL,
121 NULL);
122 _check_for_disconnect(user, rc);
124 } else {
125 PurpleConnectionError reason;
126 char *err = g_strdup_printf(_("Unable to login: %s"),
127 nm_error_to_string (ret_code));
129 switch (ret_code) {
130 case NMERR_AUTHENTICATION_FAILED:
131 case NMERR_CREDENTIALS_MISSING:
132 case NMERR_PASSWORD_INVALID:
133 /* Don't attempt to auto-reconnect if our
134 * password was invalid.
136 if (!purple_account_get_remember_password(purple_connection_get_account(gc)))
137 purple_account_set_password(purple_connection_get_account(gc), NULL, NULL, NULL);
138 reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
139 break;
140 default:
141 /* FIXME: There are other reasons login could fail */
142 reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
145 purple_connection_error(gc, reason, err);
146 g_free(err);
150 /* Handle getstatus response*/
151 static void
152 _get_status_resp_cb(NMUser * user, NMERR_T ret_code,
153 gpointer resp_data, gpointer user_data)
155 PurpleBuddy *buddy;
156 GSList *buddies;
157 GSList *bnode;
158 NMUserRecord *user_record = (NMUserRecord *) resp_data;
159 int status;
161 if (user == NULL || user_record == NULL)
162 return;
164 if (ret_code == NM_OK) {
166 /* Find all Purple buddies and update their statuses */
167 const char *name = nm_user_record_get_display_id(user_record);
169 if (name) {
170 buddies = purple_blist_find_buddies((PurpleAccount *) user->client_data, name);
171 for (bnode = buddies; bnode; bnode = bnode->next) {
172 buddy = (PurpleBuddy *) bnode->data;
173 if (buddy) {
174 status = nm_user_record_get_status(user_record);
175 _update_buddy_status(user, buddy, status, time(0));
178 g_slist_free(buddies);
181 } else {
183 purple_debug(PURPLE_DEBUG_INFO, "novell",
184 "_get_status_resp_cb(): rc = 0x%X\n", ret_code);
189 /* Show an error if the rename failed */
190 static void
191 _rename_contact_resp_cb(NMUser * user, NMERR_T ret_code,
192 gpointer resp_data, gpointer user_data)
194 if (ret_code != NM_OK) {
195 purple_debug(PURPLE_DEBUG_INFO, "novell",
196 "_rename_contact_resp_cb(): rc = 0x%X\n", ret_code);
200 /* Handle the getdetails response and send the message */
201 static void
202 _get_details_resp_send_msg(NMUser * user, NMERR_T ret_code,
203 gpointer resp_data, gpointer user_data)
205 PurpleConversation *gconv;
206 PurpleConnection *gc;
207 NMUserRecord *user_record = NULL;
208 NMContact *cntct = NULL;
209 NMConference *conf;
210 NMMessage *msg = user_data;
211 const char *dn = NULL;
212 const char *name;
214 if (user == NULL || msg == NULL)
215 return;
217 if (ret_code == NM_OK) {
218 user_record = (NMUserRecord *) resp_data;
219 if (user_record) {
221 /* Set the title for the conversation */
222 /* XXX - Should this be find_im_with_account? */
223 gconv = purple_conversations_find_with_account(nm_user_record_get_display_id(user_record),
224 (PurpleAccount *) user->client_data);
225 if (gconv) {
227 dn = nm_user_record_get_dn(user_record);
228 if (dn) {
229 cntct = nm_find_contact(user, dn);
232 if (cntct) {
233 purple_conversation_set_title(gconv,
234 nm_contact_get_display_name(cntct));
235 } else {
237 /* Not in the contact list, try to user full name */
238 name = (char *) nm_user_record_get_full_name(user_record);
239 if (name)
240 purple_conversation_set_title(gconv, name);
244 /* Add the user record to particpant list */
245 conf = nm_message_get_conference(msg);
246 if (conf) {
247 nm_conference_add_participant(conf, user_record);
248 _send_message(user, msg);
252 } else {
254 gc = purple_account_get_connection(user->client_data);
255 if (gc != NULL) {
256 char *err = g_strdup_printf(_("Unable to send message."
257 " Could not get details for user (%s)."),
258 nm_error_to_string (ret_code));
260 purple_notify_error(gc, NULL, err, NULL,
261 purple_request_cpar_from_connection(gc));
262 g_free(err);
265 nm_release_message(msg);
269 /* Set up the new PurpleBuddy based on the response from getdetails */
270 static void
271 _get_details_resp_setup_buddy(NMUser * user, NMERR_T ret_code,
272 gpointer resp_data, gpointer user_data)
274 NMUserRecord *user_record;
275 NMContact *contact;
276 PurpleBuddy *buddy;
277 const char *alias;
278 NMERR_T rc = NM_OK;
280 if (user == NULL || resp_data == NULL || user_data == NULL)
281 return;
283 contact = user_data;
285 if (ret_code == NM_OK) {
286 user_record = resp_data;
288 buddy = nm_contact_get_data(contact);
290 nm_contact_set_user_record(contact, user_record);
292 /* Set the display id */
293 purple_buddy_set_name(buddy,
294 nm_user_record_get_display_id(user_record));
296 alias = purple_buddy_get_alias(buddy);
297 if (alias == NULL || *alias == '\0' || purple_strequal(alias, purple_buddy_get_name(buddy))) {
298 purple_buddy_set_local_alias(buddy,
299 nm_user_record_get_full_name(user_record));
301 /* Tell the server about the new display name */
302 rc = nm_send_rename_contact(user, contact,
303 nm_user_record_get_full_name(user_record),
304 NULL, NULL);
305 _check_for_disconnect(user, rc);
310 /* Get initial status for the buddy */
311 rc = nm_send_get_status(user, resp_data, _get_status_resp_cb, NULL);
312 _check_for_disconnect(user, rc);
314 /* nm_release_contact(contact);*/
318 nm_release_contact(contact);
321 /* Add the new contact into the PurpleBuddy list */
322 static void
323 _create_contact_resp_cb(NMUser * user, NMERR_T ret_code,
324 gpointer resp_data, gpointer user_data)
326 NMContact *tmp_contact = (NMContact *) user_data;
327 NMContact *new_contact = NULL;
328 NMFolder *folder = NULL;
329 PurpleGroup *group;
330 PurpleBuddy *buddy;
331 const char *folder_name = NULL;
332 NMERR_T rc = NM_OK;
334 if (user == NULL)
335 return;
337 if (ret_code == NM_OK) {
339 new_contact = (NMContact *) resp_data;
340 if (new_contact == NULL || tmp_contact == NULL)
341 return;
343 /* Get the userid and folder name for the new contact */
344 folder = nm_find_folder_by_id(user,
345 nm_contact_get_parent_id(new_contact));
346 if (folder) {
347 folder_name = nm_folder_get_name(folder);
350 if (folder_name == NULL || *folder_name == '\0')
351 folder_name = NM_ROOT_FOLDER_NAME;
353 /* Re-add the buddy now that we got the okay from the server */
354 group = purple_blist_find_group(folder_name);
355 if (group) {
356 const char *alias = nm_contact_get_display_name(tmp_contact);
357 const char *display_id = nm_contact_get_display_id(new_contact);
359 if (display_id == NULL)
360 display_id = nm_contact_get_dn(new_contact);
362 if (alias && !purple_strequal(alias, display_id)) {
364 /* The user requested an alias, tell the server about it. */
365 rc = nm_send_rename_contact(user, new_contact, alias,
366 _rename_contact_resp_cb, NULL);
367 _check_for_disconnect(user, rc);
369 } else {
371 alias = "";
375 /* Add it to the purple buddy list if it is not there */
376 buddy = purple_blist_find_buddy_in_group(user->client_data, display_id, group);
377 if (buddy == NULL) {
378 buddy = purple_buddy_new(user->client_data, display_id, alias);
379 purple_blist_add_buddy(buddy, NULL, group, NULL);
382 /* Save the new buddy as part of the contact object */
383 nm_contact_set_data(new_contact, (gpointer) buddy);
385 /* We need details for the user before we can setup the
386 * new Purple buddy. We always call this because the
387 * 'createcontact' response fields do not always contain
388 * everything that we need.
390 nm_contact_add_ref(new_contact);
392 rc = nm_send_get_details(user, nm_contact_get_dn(new_contact),
393 _get_details_resp_setup_buddy, new_contact);
394 _check_for_disconnect(user, rc);
397 } else {
398 PurpleConnection *gc = purple_account_get_connection(user->client_data);
399 const char *name = nm_contact_get_dn(tmp_contact);
400 char *err;
402 err =
403 g_strdup_printf(_("Unable to add %s to your buddy list (%s)."),
404 name, nm_error_to_string (ret_code));
405 purple_notify_error(gc, NULL, err, NULL,
406 purple_request_cpar_from_connection(gc));
407 g_free(err);
411 if (tmp_contact)
412 nm_release_contact(tmp_contact);
415 /* Show an error if we failed to send the message */
416 static void
417 _send_message_resp_cb(NMUser * user, NMERR_T ret_code,
418 gpointer resp_data, gpointer user_data)
420 PurpleConnection *gc;
421 char *err = NULL;
423 if (user == NULL)
424 return;
426 if (ret_code != NM_OK) {
427 gc = purple_account_get_connection(user->client_data);
429 /* TODO: Improve this! message to who or for what conference? */
430 err = g_strdup_printf(_("Unable to send message (%s)."),
431 nm_error_to_string (ret_code));
432 purple_notify_error(gc, NULL, err, NULL,
433 purple_request_cpar_from_connection(gc));
434 g_free(err);
438 /* Show an error if the remove failed */
439 static void
440 _remove_contact_resp_cb(NMUser * user, NMERR_T ret_code,
441 gpointer resp_data, gpointer user_data)
443 if (ret_code != NM_OK) {
444 /* TODO: Display an error? */
446 purple_debug(PURPLE_DEBUG_INFO, "novell",
447 "_remove_contact_resp_cb(): rc = 0x%x\n", ret_code);
451 /* Show an error if the remove failed */
452 static void
453 _remove_folder_resp_cb(NMUser * user, NMERR_T ret_code,
454 gpointer resp_data, gpointer user_data)
456 if (ret_code != NM_OK) {
457 /* TODO: Display an error? */
459 purple_debug(PURPLE_DEBUG_INFO, "novell",
460 "_remove_folder_resp_cb(): rc = 0x%x\n", ret_code);
464 /* Show an error if the move failed */
465 static void
466 _move_contact_resp_cb(NMUser * user, NMERR_T ret_code,
467 gpointer resp_data, gpointer user_data)
469 if (ret_code != NM_OK) {
470 /* TODO: Display an error? */
472 purple_debug(PURPLE_DEBUG_INFO, "novell",
473 "_move_contact_resp_cb(): rc = 0x%x\n", ret_code);
477 /* Show an error if the rename failed */
478 static void
479 _rename_folder_resp_cb(NMUser * user, NMERR_T ret_code,
480 gpointer resp_data, gpointer user_data)
482 if (ret_code != NM_OK) {
483 /* TODO: Display an error? */
485 purple_debug(PURPLE_DEBUG_INFO, "novell",
486 "_rename_folder_resp_cb(): rc = 0x%x\n", ret_code);
490 static void
491 _sendinvite_resp_cb(NMUser *user, NMERR_T ret_code,
492 gpointer resp_data, gpointer user_data)
494 char *err;
495 PurpleConnection *gc;
497 if (user == NULL)
498 return;
500 if (ret_code != NM_OK) {
501 gc = purple_account_get_connection(user->client_data);
502 err = g_strdup_printf(_("Unable to invite user (%s)."), nm_error_to_string(ret_code));
503 purple_notify_error(gc, NULL, err, NULL,
504 purple_request_cpar_from_connection(gc));
505 g_free(err);
507 purple_debug(PURPLE_DEBUG_INFO, "novell",
508 "_sendinvite_resp_cb(): rc = 0x%x\n", ret_code);
513 /* If the createconf was successful attempt to send the message,
514 * otherwise display an error message to the user.
516 static void
517 _createconf_resp_send_msg(NMUser * user, NMERR_T ret_code,
518 gpointer resp_data, gpointer user_data)
520 NMConference *conf;
521 NMMessage *msg = user_data;
523 if (user == NULL || msg == NULL)
524 return;
526 if (ret_code == NM_OK) {
527 _send_message(user, msg);
528 } else {
530 if ((conf = nm_message_get_conference(msg))) {
532 PurpleConnection *gc = purple_account_get_connection(user->client_data);
533 const char *name = NULL;
534 char *err;
535 NMUserRecord *ur;
537 ur = nm_conference_get_participant(conf, 0);
538 if (ur)
539 name = nm_user_record_get_userid(ur);
541 if (name)
542 err = g_strdup_printf(_("Unable to send message to %s."
543 " Could not create the conference (%s)."),
544 name,
545 nm_error_to_string (ret_code));
546 else
547 err = g_strdup_printf(_("Unable to send message."
548 " Could not create the conference (%s)."),
549 nm_error_to_string (ret_code));
551 purple_notify_error(gc, NULL, err, NULL,
552 purple_request_cpar_from_connection(gc));
553 g_free(err);
556 nm_release_message(msg);
560 /* Move contact to newly created folder */
561 static void
562 _create_folder_resp_move_contact(NMUser * user, NMERR_T ret_code,
563 gpointer resp_data, gpointer user_data)
565 NMContact *contact = user_data;
566 NMFolder *new_folder;
567 char *folder_name = resp_data;
568 NMERR_T rc = NM_OK;
570 if (user == NULL || folder_name == NULL || contact == NULL) {
572 g_free(folder_name);
574 return;
577 if (ret_code == NM_OK || ret_code == NMERR_DUPLICATE_FOLDER) {
578 new_folder = nm_find_folder(user, folder_name);
579 if (new_folder) {
581 /* Tell the server to move the contact to the new folder */
582 /* rc = nm_send_move_contact(user, contact, new_folder,
583 _move_contact_resp_cb, NULL); */
585 rc = nm_send_create_contact(user, new_folder, contact,
586 NULL, NULL);
588 _check_for_disconnect(user, rc);
591 } else {
592 PurpleConnection *gc = purple_account_get_connection(user->client_data);
593 char *err = g_strdup_printf(_("Unable to move user %s"
594 " to folder %s in the server side list."
595 " Error while creating folder (%s)."),
596 nm_contact_get_dn(contact),
597 folder_name,
598 nm_error_to_string (ret_code));
600 purple_notify_error(gc, NULL, err, NULL,
601 purple_request_cpar_from_connection(gc));
602 g_free(err);
605 g_free(folder_name);
608 /* Add contact to newly create folder */
609 static void
610 _create_folder_resp_add_contact(NMUser * user, NMERR_T ret_code,
611 gpointer resp_data, gpointer user_data)
613 NMContact *contact = (NMContact *) user_data;
614 NMFolder *folder;
615 char *folder_name = (char *) resp_data;
616 NMERR_T rc = NM_OK;
618 if (user == NULL || folder_name == NULL || contact == NULL) {
620 if (contact)
621 nm_release_contact(contact);
623 g_free(folder_name);
625 return;
628 if (ret_code == NM_OK || ret_code == NMERR_DUPLICATE_FOLDER) {
629 folder = nm_find_folder(user, folder_name);
630 if (folder) {
632 rc = nm_send_create_contact(user, folder, contact,
633 _create_contact_resp_cb, contact);
634 _check_for_disconnect(user, rc);
636 } else {
637 PurpleConnection *gc = purple_account_get_connection(user->client_data);
638 const char *name = nm_contact_get_dn(contact);
639 char *err =
640 g_strdup_printf(_("Unable to add %s to your buddy list."
641 " Error creating folder in server side list (%s)."),
642 name, nm_error_to_string (ret_code));
644 purple_notify_error(gc, NULL, err, NULL,
645 purple_request_cpar_from_connection(gc));
647 nm_release_contact(contact);
648 g_free(err);
651 g_free(folder_name);
654 static void
655 _join_conf_resp_cb(NMUser * user, NMERR_T ret_code,
656 gpointer resp_data, gpointer user_data)
658 PurpleChatConversation *chat;
659 PurpleConnection *gc;
660 NMUserRecord *ur;
661 NMConference *conference = user_data;
662 const char *name, *conf_name;
663 int i, count;
665 if (user == NULL || conference == NULL)
666 return;
668 gc = purple_account_get_connection(user->client_data);
670 if (ret_code == NM_OK) {
671 conf_name = _get_conference_name(++user->conference_count);
672 chat = purple_serv_got_joined_chat(gc, user->conference_count, conf_name);
673 if (chat) {
675 nm_conference_set_data(conference, (gpointer) chat);
677 count = nm_conference_get_participant_count(conference);
678 for (i = 0; i < count; i++) {
679 ur = nm_conference_get_participant(conference, i);
680 if (ur) {
681 name = nm_user_record_get_display_id(ur);
682 purple_chat_conversation_add_user(chat, name, NULL,
683 PURPLE_CHAT_USER_NONE, TRUE);
690 /* Show info returned by getdetails */
691 static void
692 _get_details_resp_show_info(NMUser * user, NMERR_T ret_code,
693 gpointer resp_data, gpointer user_data)
695 PurpleConnection *gc;
696 NMUserRecord *user_record;
697 char *name;
698 char *err;
700 if (user == NULL)
701 return;
703 name = user_data;
705 if (ret_code == NM_OK) {
706 user_record = (NMUserRecord *) resp_data;
707 if (user_record) {
708 _show_info(purple_account_get_connection(user->client_data),
709 user_record, g_strdup(name));
711 } else {
712 gc = purple_account_get_connection(user->client_data);
713 err =
714 g_strdup_printf(_("Could not get details for user %s (%s)."),
715 name, nm_error_to_string (ret_code));
716 purple_notify_error(gc, NULL, err, NULL,
717 purple_request_cpar_from_connection(gc));
718 g_free(err);
721 g_free(name);
724 /* Handle get details response add to privacy list */
725 static void
726 _get_details_resp_add_privacy_item(NMUser *user, NMERR_T ret_code,
727 gpointer resp_data, gpointer user_data)
729 PurpleConnection *gc;
730 PurpleAccount *account;
731 NMUserRecord *user_record = resp_data;
732 char *err;
733 gboolean allowed = GPOINTER_TO_INT(user_data);
734 const char *display_id;
736 if (user == NULL)
737 return;
739 gc = purple_account_get_connection(user->client_data);
740 display_id = nm_user_record_get_display_id(user_record);
741 account = purple_connection_get_account(gc);
743 if (ret_code == NM_OK) {
745 if (allowed) {
747 if (!g_slist_find_custom(purple_account_privacy_get_denied(account),
748 display_id, (GCompareFunc)purple_utf8_strcasecmp)) {
749 purple_account_privacy_permit_add(account, display_id, TRUE);
752 } else {
754 if (!g_slist_find_custom(purple_account_privacy_get_denied(account),
755 display_id, (GCompareFunc)purple_utf8_strcasecmp)) {
756 purple_account_privacy_deny_add(account, display_id, TRUE);
760 } else {
762 err = g_strdup_printf(_("Unable to add user to privacy list (%s)."),
763 nm_error_to_string(ret_code));
764 purple_notify_error(gc, NULL, err, NULL,
765 purple_request_cpar_from_connection(gc));
766 g_free(err);
771 /* Handle response to create privacy item request */
772 static void
773 _create_privacy_item_deny_resp_cb(NMUser *user, NMERR_T ret_code,
774 gpointer resp_data, gpointer user_data)
776 PurpleConnection *gc;
777 PurpleAccount *account;
778 NMUserRecord *user_record;
779 char *who = user_data;
780 char *err;
781 NMERR_T rc = NM_OK;
782 const char *display_id = NULL;
784 if (user == NULL)
785 return;
787 gc = purple_account_get_connection(user->client_data);
788 account = purple_connection_get_account(gc);
790 if (ret_code == NM_OK) {
792 user_record = nm_find_user_record(user, who);
793 if (user_record)
794 display_id = nm_user_record_get_display_id(user_record);
796 if (display_id) {
798 if (!g_slist_find_custom(purple_account_privacy_get_denied(account),
799 display_id, (GCompareFunc)purple_utf8_strcasecmp)) {
801 purple_account_privacy_deny_add(account, display_id, TRUE);
804 } else {
805 rc = nm_send_get_details(user, who,
806 _get_details_resp_add_privacy_item,
807 GINT_TO_POINTER(FALSE));
808 _check_for_disconnect(user, rc);
810 } else {
812 err = g_strdup_printf(_("Unable to add %s to deny list (%s)."),
813 who, nm_error_to_string(ret_code));
814 purple_notify_error(gc, NULL, err, NULL,
815 purple_request_cpar_from_connection(gc));
816 g_free(err);
820 g_free(who);
824 /* Handle response to create privacy item request */
825 static void
826 _create_privacy_item_permit_resp_cb(NMUser *user, NMERR_T ret_code,
827 gpointer resp_data, gpointer user_data)
829 PurpleConnection *gc;
830 PurpleAccount *account;
831 NMUserRecord *user_record;
832 char *who = user_data;
833 char *err;
834 NMERR_T rc = NM_OK;
835 const char *display_id = NULL;
837 if (user == NULL)
838 return;
840 gc = purple_account_get_connection(user->client_data);
841 account = purple_connection_get_account(gc);
843 if (ret_code == NM_OK) {
845 user_record = nm_find_user_record(user, who);
846 if (user_record)
847 display_id = nm_user_record_get_display_id(user_record);
849 if (display_id) {
851 if (!g_slist_find_custom(purple_account_privacy_get_permitted(account),
852 display_id,
853 (GCompareFunc)purple_utf8_strcasecmp)) {
855 purple_account_privacy_permit_add(account, display_id, TRUE);
858 } else {
859 rc = nm_send_get_details(user, who,
860 _get_details_resp_add_privacy_item,
861 GINT_TO_POINTER(TRUE));
862 _check_for_disconnect(user, rc);
865 } else {
867 err = g_strdup_printf(_("Unable to add %s to permit list (%s)."), who,
868 nm_error_to_string(ret_code));
869 purple_notify_error(gc, NULL, err, NULL,
870 purple_request_cpar_from_connection(gc));
871 g_free(err);
875 g_free(who);
878 static void
879 _get_details_send_privacy_create(NMUser *user, NMERR_T ret_code,
880 gpointer resp_data, gpointer user_data)
882 NMERR_T rc = NM_OK;
883 PurpleConnection *gc;
884 NMUserRecord *user_record = resp_data;
885 char *err;
886 gboolean allowed = GPOINTER_TO_INT(user_data);
887 const char *dn, *display_id;
889 if (user == NULL)
890 return;
892 gc = purple_account_get_connection(user->client_data);
893 dn = nm_user_record_get_dn(user_record);
894 display_id = nm_user_record_get_display_id(user_record);
896 if (ret_code == NM_OK) {
898 if (allowed) {
899 rc = nm_send_create_privacy_item(user, dn, TRUE,
900 _create_privacy_item_permit_resp_cb,
901 g_strdup(display_id));
902 _check_for_disconnect(user, rc);
904 } else {
905 rc = nm_send_create_privacy_item(user, dn, FALSE,
906 _create_privacy_item_deny_resp_cb,
907 g_strdup(display_id));
908 _check_for_disconnect(user, rc);
911 } else {
913 err = g_strdup_printf(_("Unable to add user to privacy list (%s)."),
914 nm_error_to_string(ret_code));
915 purple_notify_error(gc, NULL, err, NULL,
916 purple_request_cpar_from_connection(gc));
917 g_free(err);
922 static void
923 _remove_privacy_item_resp_cb(NMUser *user, NMERR_T ret_code,
924 gpointer resp_data, gpointer user_data)
926 PurpleConnection *gc;
927 char *who = user_data;
928 char *err;
930 if (user == NULL)
931 return;
933 if (ret_code != NM_OK) {
935 gc = purple_account_get_connection(user->client_data);
936 err = g_strdup_printf(_("Unable to remove %s from privacy list (%s)."), who,
937 nm_error_to_string(ret_code));
938 purple_notify_error(gc, NULL, err, NULL,
939 purple_request_cpar_from_connection(gc));
940 g_free(err);
943 g_free(who);
946 static void
947 _set_privacy_default_resp_cb(NMUser *user, NMERR_T ret_code,
948 gpointer resp_data, gpointer user_data)
950 PurpleConnection *gc;
951 char *err;
953 if (user == NULL)
954 return;
956 if (ret_code != NM_OK) {
958 gc = purple_account_get_connection(user->client_data);
959 err = g_strdup_printf(_("Unable to change server side privacy settings (%s)."),
960 nm_error_to_string(ret_code));
961 purple_notify_error(gc, NULL, err, NULL,
962 purple_request_cpar_from_connection(gc));
963 g_free(err);
968 /* Handle get details response add to privacy list */
969 static void
970 _get_details_resp_send_invite(NMUser *user, NMERR_T ret_code,
971 gpointer resp_data, gpointer user_data)
973 NMERR_T rc = NM_OK;
974 PurpleConnection *gc;
975 NMUserRecord *user_record = resp_data;
976 char *err;
977 GSList *cnode;
978 NMConference *conference;
979 gpointer chat;
980 int id = GPOINTER_TO_INT(user_data);
982 if (user == NULL)
983 return;
985 gc = purple_account_get_connection(user->client_data);
987 if (ret_code == NM_OK) {
989 for (cnode = user->conferences; cnode != NULL; cnode = cnode->next) {
990 conference = cnode->data;
991 if (conference && (chat = nm_conference_get_data(conference))) {
992 if (purple_chat_conversation_get_id(PURPLE_CHAT_CONVERSATION(chat)) == id) {
993 rc = nm_send_conference_invite(user, conference, user_record,
994 NULL, _sendinvite_resp_cb, NULL);
995 _check_for_disconnect(user, rc);
996 break;
1001 } else {
1003 err = g_strdup_printf(_("Unable to invite user (%s)."), nm_error_to_string(ret_code));
1004 purple_notify_error(gc, NULL, err, NULL,
1005 purple_request_cpar_from_connection(gc));
1006 g_free(err);
1011 static void
1012 _createconf_resp_send_invite(NMUser * user, NMERR_T ret_code,
1013 gpointer resp_data, gpointer user_data)
1015 NMERR_T rc = NM_OK;
1016 NMConference *conference = resp_data;
1017 NMUserRecord *user_record = user_data;
1018 PurpleConnection *gc;
1019 char *err;
1021 if (user == NULL)
1022 return;
1026 if (ret_code == NM_OK) {
1027 rc = nm_send_conference_invite(user, conference, user_record,
1028 NULL, _sendinvite_resp_cb, NULL);
1029 _check_for_disconnect(user, rc);
1030 } else {
1031 err = g_strdup_printf(_("Unable to create conference (%s)."), nm_error_to_string(ret_code));
1032 gc = purple_account_get_connection(user->client_data);
1033 purple_notify_error(gc, NULL, err, NULL,
1034 purple_request_cpar_from_connection(gc));
1035 g_free(err);
1039 /*******************************************************************************
1040 * Helper functions
1041 ******************************************************************************/
1043 static char *
1044 _user_agent_string(void)
1047 #if !defined(_WIN32)
1049 const char *sysname = "";
1050 const char *release = "";
1051 struct utsname u;
1053 if (uname(&u) == 0) {
1054 sysname = u.sysname;
1055 release = u.release;
1056 } else {
1057 sysname = "Linux";
1058 release = "Unknown";
1061 return g_strdup_printf("Purple/%s (%s; %s)", VERSION, sysname, release);
1063 #else
1065 const char *sysname = "";
1066 OSVERSIONINFO os_info;
1067 SYSTEM_INFO sys_info;
1069 os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1070 GetVersionEx(&os_info);
1071 GetSystemInfo(&sys_info);
1073 if (os_info.dwPlatformId == VER_PLATFORM_WIN32_NT) {
1074 switch (os_info.dwMajorVersion) {
1075 case 3:
1076 case 4:
1077 sysname = "Windows NT";
1078 break;
1079 case 5:
1080 switch (os_info.dwMinorVersion) {
1081 case 0:
1082 sysname = "Windows 2000";
1083 break;
1084 case 1:
1085 sysname = "Windows XP";
1086 break;
1087 case 2:
1088 sysname = "Windows Server 2003";
1089 break;
1090 default:
1091 sysname = "Windows";
1092 break;
1094 break;
1095 default:
1096 sysname = "Windows";
1097 break;
1100 } else if (os_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
1101 switch (os_info.dwMinorVersion) {
1102 case 0:
1103 sysname = "Windows 95";
1104 break;
1105 case 10:
1106 sysname = "Windows 98";
1107 break;
1108 case 90:
1109 sysname = "Windows ME";
1110 break;
1111 default:
1112 sysname = "Windows";
1113 break;
1115 } else {
1116 sysname = "Windows";
1119 return g_strdup_printf("Purple/%s (%s; %ld.%ld)", VERSION, sysname,
1120 os_info.dwMajorVersion, os_info.dwMinorVersion);
1122 #endif
1127 static gboolean
1128 _is_disconnect_error(NMERR_T err)
1130 return (err == NMERR_TCP_WRITE ||
1131 err == NMERR_TCP_READ || err == NMERR_PROTOCOL);
1134 static gboolean
1135 _check_for_disconnect(NMUser * user, NMERR_T err)
1137 PurpleConnection *gc = purple_account_get_connection(user->client_data);
1139 if (_is_disconnect_error(err)) {
1141 purple_connection_error(gc,
1142 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
1143 _("Error communicating with server. Closing connection."));
1144 return TRUE;
1148 return FALSE;
1151 /* Check to see if the conference is instantiated, if so send the message.
1152 * If not send the create conference -- the response handler for the createconf
1153 * will call this function again.
1155 static void
1156 _send_message(NMUser * user, NMMessage * message)
1158 NMConference *conf;
1159 NMERR_T rc = NM_OK;
1161 conf = nm_message_get_conference(message);
1162 if (conf) {
1163 /* We have a conference make sure that the
1164 server knows about it already. */
1165 if (nm_conference_is_instantiated(conf)) {
1167 /* We have everything that we need...finally! */
1168 rc = nm_send_message(user, message, _send_message_resp_cb);
1169 _check_for_disconnect(user, rc);
1171 nm_release_message(message);
1173 } else {
1174 rc = nm_send_create_conference(user, conf, _createconf_resp_send_msg, message);
1175 _check_for_disconnect(user, rc);
1181 * Update the status of the given buddy in the Purple buddy list
1183 static void
1184 _update_buddy_status(NMUser *user, PurpleBuddy * buddy, int novellstatus, int gmt)
1186 PurpleAccount *account;
1187 const char *status_id;
1188 const char *text = NULL;
1189 const char *dn;
1190 const char *name;
1191 int idle = 0;
1193 account = purple_buddy_get_account(buddy);
1194 name = purple_buddy_get_name(buddy);
1196 switch (novellstatus) {
1197 case NM_STATUS_AVAILABLE:
1198 status_id = NOVELL_STATUS_TYPE_AVAILABLE;
1199 break;
1200 case NM_STATUS_AWAY:
1201 status_id = NOVELL_STATUS_TYPE_AWAY;
1202 break;
1203 case NM_STATUS_BUSY:
1204 status_id = NOVELL_STATUS_TYPE_BUSY;
1205 break;
1206 case NM_STATUS_OFFLINE:
1207 status_id = NOVELL_STATUS_TYPE_OFFLINE;
1208 break;
1209 case NM_STATUS_AWAY_IDLE:
1210 status_id = NOVELL_STATUS_TYPE_AWAY;
1211 idle = gmt;
1212 break;
1213 default:
1214 status_id = NOVELL_STATUS_TYPE_OFFLINE;
1215 break;
1218 /* Get status text for the user */
1219 dn = nm_lookup_dn(user, name);
1220 if (dn) {
1221 NMUserRecord *user_record = nm_find_user_record(user, dn);
1222 if (user_record) {
1223 text = nm_user_record_get_status_text(user_record);
1227 purple_protocol_got_user_status(account, name, status_id,
1228 "message", text, NULL);
1229 purple_protocol_got_user_idle(account, name,
1230 (novellstatus == NM_STATUS_AWAY_IDLE), idle);
1233 /* Iterate through the cached Purple buddy list and remove buddies
1234 * that are not in the server side list.
1236 static void
1237 _remove_purple_buddies(NMUser *user)
1239 PurpleBlistNode *gnode;
1240 PurpleBlistNode *cnode;
1241 PurpleBlistNode *bnode;
1242 PurpleGroup *group;
1243 PurpleBuddy *buddy;
1244 GSList *rem_list = NULL;
1245 NMFolder *folder = NULL;
1246 const char *gname = NULL;
1248 for (gnode = purple_blist_get_default_root(); gnode;
1249 gnode = purple_blist_node_get_sibling_next(gnode)) {
1250 if (!PURPLE_IS_GROUP(gnode))
1251 continue;
1252 group = (PurpleGroup *) gnode;
1253 gname = purple_group_get_name(group);
1254 for (cnode = purple_blist_node_get_first_child(gnode);
1255 cnode;
1256 cnode = purple_blist_node_get_sibling_next(cnode)) {
1257 if (!PURPLE_IS_CONTACT(cnode))
1258 continue;
1259 for (bnode = purple_blist_node_get_first_child(cnode);
1260 bnode;
1261 bnode = purple_blist_node_get_sibling_next(bnode)) {
1262 if (!PURPLE_IS_BUDDY(bnode))
1263 continue;
1264 buddy = (PurpleBuddy *) bnode;
1265 if (purple_buddy_get_account(buddy) == user->client_data) {
1266 if (purple_strequal(gname, NM_ROOT_FOLDER_NAME))
1267 gname = "";
1268 folder = nm_find_folder(user, gname);
1269 if (folder == NULL ||
1270 !nm_folder_find_contact_by_display_id(folder, purple_buddy_get_name(buddy))) {
1271 rem_list = g_slist_append(rem_list, buddy);
1278 g_slist_free_full(rem_list, (GDestroyNotify)purple_blist_remove_buddy);
1281 /* Add all of the contacts in the given folder to the Purple buddy list */
1282 static void
1283 _add_contacts_to_purple_blist(NMUser * user, NMFolder * folder)
1285 NMUserRecord *user_record = NULL;
1286 NMContact *contact = NULL;
1287 PurpleBuddy *buddy = NULL;
1288 PurpleGroup *group;
1289 NMERR_T cnt = 0, i;
1290 const char *name = NULL;
1291 const char *fname = NULL;
1292 int status = 0;
1294 /* If this is the root folder give it a name. Purple does not have the concept of
1295 * a root folder.
1297 fname = nm_folder_get_name(folder);
1298 if (fname == NULL || *fname == '\0') {
1299 fname = NM_ROOT_FOLDER_NAME;
1302 /* Does the Purple group exist already? */
1303 group = purple_blist_find_group(fname);
1304 if (group == NULL) {
1305 group = purple_group_new(fname);
1306 purple_blist_add_group(group, NULL);
1309 /* Get each contact for this folder */
1310 cnt = nm_folder_get_contact_count(folder);
1311 for (i = 0; i < cnt; i++) {
1312 contact = nm_folder_get_contact(folder, i);
1313 if (contact) {
1315 name = nm_contact_get_display_id(contact);
1316 if (name) {
1318 buddy = purple_blist_find_buddy_in_group(user->client_data, name, group);
1319 if (buddy == NULL) {
1320 /* Add it to the purple buddy list */
1321 buddy = purple_buddy_new(user->client_data,
1322 name,
1323 nm_contact_get_display_name(contact));
1325 purple_blist_add_buddy(buddy, NULL, group, NULL);
1328 /* Set the initial status for the buddy */
1329 user_record = nm_contact_get_user_record(contact);
1330 if (user_record) {
1331 status = nm_user_record_get_status(user_record);
1333 _update_buddy_status(user, buddy, status, time(0));
1335 /* Save the new buddy as part of the contact object */
1336 nm_contact_set_data(contact, (gpointer) buddy);
1339 } else {
1340 /* NULL contact. This should not happen, but
1341 * let's break out of the loop.
1343 break;
1348 /* Add all of the server side contacts to the Purple buddy list. */
1349 static void
1350 _add_purple_buddies(NMUser * user)
1352 int cnt = 0, i;
1353 NMFolder *root_folder = NULL;
1354 NMFolder *folder = NULL;
1356 root_folder = nm_get_root_folder(user);
1357 if (root_folder) {
1359 /* Add sub-folders and contacts to sub-folders...
1360 * iterate throught the sub-folders in reverse order
1361 * because Purple adds the folders to the front -- so we
1362 * want to add the first folder last
1364 cnt = nm_folder_get_subfolder_count(root_folder);
1365 for (i = cnt-1; i >= 0; i--) {
1366 folder = nm_folder_get_subfolder(root_folder, i);
1367 if (folder) {
1368 _add_contacts_to_purple_blist(user, folder);
1372 /* Add contacts for the root folder */
1373 _add_contacts_to_purple_blist(user, root_folder);
1377 static void
1378 _sync_contact_list(NMUser *user)
1380 /* Remove all buddies from the local list that are
1381 * not in the server side list and add all buddies
1382 * from the server side list that are not in
1383 * the local list
1385 _remove_purple_buddies(user);
1386 _add_purple_buddies(user);
1387 user->clist_synched = TRUE;
1390 static void
1391 _sync_privacy_lists(NMUser *user)
1393 GSList *node = NULL, *rem_list = NULL;
1394 PurpleConnection *gc;
1395 PurpleAccount *account;
1396 const char *name, *dn;
1397 NMUserRecord *user_record;
1399 if (user == NULL)
1400 return;
1402 gc = purple_account_get_connection(user->client_data);
1403 if (gc == NULL)
1404 return;
1406 account = purple_connection_get_account(gc);
1408 /* Set the Purple privacy setting */
1409 if (user->default_deny) {
1410 if (user->allow_list == NULL) {
1411 purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_DENY_ALL);
1412 } else {
1413 purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS);
1415 } else {
1416 if (user->deny_list == NULL) {
1417 purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL);
1418 } else {
1419 purple_account_set_privacy_type(account, PURPLE_ACCOUNT_PRIVACY_DENY_USERS);
1423 /* Add stuff */
1424 for (node = user->allow_list; node; node = node->next) {
1425 user_record = nm_find_user_record(user, (char *)node->data);
1426 if (user_record)
1427 name = nm_user_record_get_display_id(user_record);
1428 else
1429 name =(char *)node->data;
1431 if (!g_slist_find_custom(purple_account_privacy_get_permitted(account),
1432 name, (GCompareFunc)purple_utf8_strcasecmp)) {
1433 purple_account_privacy_permit_add(account, name , TRUE);
1437 for (node = user->deny_list; node; node = node->next) {
1438 user_record = nm_find_user_record(user, (char *)node->data);
1439 if (user_record)
1440 name = nm_user_record_get_display_id(user_record);
1441 else
1442 name =(char *)node->data;
1444 if (!g_slist_find_custom(purple_account_privacy_get_denied(account),
1445 name, (GCompareFunc)purple_utf8_strcasecmp)) {
1446 purple_account_privacy_deny_add(account, name, TRUE);
1451 /* Remove stuff */
1452 for (node = purple_account_privacy_get_permitted(account); node; node = node->next) {
1453 dn = nm_lookup_dn(user, (char *)node->data);
1454 if (dn != NULL &&
1455 !g_slist_find_custom(user->allow_list,
1456 dn, (GCompareFunc)purple_utf8_strcasecmp)) {
1457 rem_list = g_slist_append(rem_list, node->data);
1461 if (rem_list) {
1462 for (node = rem_list; node; node = node->next) {
1463 purple_account_privacy_permit_remove(account, (char *)node->data, TRUE);
1465 g_slist_free(rem_list);
1466 rem_list = NULL;
1469 for (node = purple_account_privacy_get_denied(account); node; node = node->next) {
1470 dn = nm_lookup_dn(user, (char *)node->data);
1471 if (dn != NULL &&
1472 !g_slist_find_custom(user->deny_list,
1473 dn, (GCompareFunc)purple_utf8_strcasecmp)) {
1474 rem_list = g_slist_append(rem_list, node->data);
1478 if (rem_list) {
1479 for (node = rem_list; node; node = node->next) {
1480 purple_account_privacy_deny_remove(account, (char *)node->data, TRUE);
1482 g_slist_free(rem_list);
1486 /* Map known property tags to user-friendly strings */
1487 static const char *
1488 _map_property_tag(const char *tag)
1490 if (tag == NULL) return NULL;
1492 if (purple_strequal(tag, "telephoneNumber"))
1493 return _("Telephone Number");
1494 else if (purple_strequal(tag, "L"))
1495 return _("Location");
1496 else if (purple_strequal(tag, "OU"))
1497 return _("Department");
1498 else if (purple_strequal(tag, "personalTitle"))
1499 return _("Personal Title");
1500 else if (purple_strequal(tag, "Title"))
1501 return _("Job Title");
1502 else if (purple_strequal(tag, "mailstop"))
1503 return _("Mailstop");
1504 else if (purple_strequal(tag, "Internet EMail Address"))
1505 return _("Email Address");
1506 else
1507 return tag;
1510 /* Display a dialog box showing the properties for the given user record */
1511 static void
1512 _show_info(PurpleConnection * gc, NMUserRecord * user_record, char * name)
1514 PurpleNotifyUserInfo *user_info = purple_notify_user_info_new();
1515 int count, i;
1516 NMProperty *property;
1517 const char *tag, *value;
1519 tag = _("User ID");
1520 value = nm_user_record_get_userid(user_record);
1521 if (value) {
1522 /* TODO: Check whether it's correct to call add_pair_html,
1523 or if we should be using add_pair_plaintext */
1524 purple_notify_user_info_add_pair_html(user_info, tag, value);
1527 tag = _("Full name");
1528 value = nm_user_record_get_full_name(user_record);
1529 if (value) {
1530 /* TODO: Check whether it's correct to call add_pair_html,
1531 or if we should be using add_pair_plaintext */
1532 purple_notify_user_info_add_pair_html(user_info, tag, value);
1535 count = nm_user_record_get_property_count(user_record);
1536 for (i = 0; i < count; i++) {
1537 property = nm_user_record_get_property(user_record, i);
1538 if (property) {
1539 tag = _map_property_tag(nm_property_get_tag(property));
1540 value = nm_property_get_value(property);
1541 if (tag && value) {
1542 /* TODO: Check whether it's correct to call add_pair_html,
1543 or if we should be using add_pair_plaintext */
1544 purple_notify_user_info_add_pair_html(user_info, tag, value);
1546 nm_release_property(property);
1550 purple_notify_userinfo(gc, name, user_info, NULL, NULL);
1551 purple_notify_user_info_destroy(user_info);
1553 g_free(name);
1556 /* Send a join conference, the first item in the parms list is the
1557 * NMUser object and the second item is the conference to join.
1558 * This callback is passed to purple_request_action when we ask the
1559 * user if they want to join the conference.
1561 static void
1562 _join_conference_cb(GSList * parms)
1564 NMUser *user;
1565 NMConference *conference;
1566 NMERR_T rc = NM_OK;
1568 if (parms == NULL || g_slist_length(parms) != 2)
1569 return;
1571 user = g_slist_nth_data(parms, 0);
1572 conference = g_slist_nth_data(parms, 1);
1574 if (user && conference) {
1575 rc = nm_send_join_conference(user, conference,
1576 _join_conf_resp_cb, conference);
1577 _check_for_disconnect(user, rc);
1580 g_slist_free(parms);
1583 /* Send a reject conference, the first item in the parms list is the
1584 * NMUser object and the second item is the conference to reject.
1585 * This callback is passed to purple_request_action when we ask the
1586 * user if they want to joing the conference.
1588 static void
1589 _reject_conference_cb(GSList * parms)
1591 NMUser *user;
1592 NMConference *conference;
1593 NMERR_T rc = NM_OK;
1595 if (parms == NULL || g_slist_length(parms) != 2)
1596 return;
1598 user = g_slist_nth_data(parms, 0);
1599 conference = g_slist_nth_data(parms, 1);
1601 if (user && conference) {
1602 rc = nm_send_reject_conference(user, conference, NULL, NULL);
1603 _check_for_disconnect(user, rc);
1606 g_slist_free(parms);
1609 static void
1610 _initiate_conference_cb(PurpleBlistNode *node, gpointer ignored)
1612 PurpleBuddy *buddy;
1613 PurpleConnection *gc;
1615 NMUser *user;
1616 const char *conf_name;
1617 PurpleChatConversation *chat = NULL;
1618 NMUserRecord *user_record;
1619 NMConference *conference;
1621 g_return_if_fail(PURPLE_IS_BUDDY(node));
1623 buddy = (PurpleBuddy *) node;
1624 gc = purple_account_get_connection(purple_buddy_get_account(buddy));
1626 user = purple_connection_get_protocol_data(gc);
1627 if (user == NULL)
1628 return;
1630 /* We should already have a userrecord for the buddy */
1631 user_record = nm_find_user_record(user, purple_buddy_get_name(buddy));
1632 if (user_record == NULL)
1633 return;
1635 conf_name = _get_conference_name(++user->conference_count);
1636 chat = purple_serv_got_joined_chat(gc, user->conference_count, conf_name);
1637 if (chat) {
1639 conference = nm_create_conference(NULL);
1640 nm_conference_set_data(conference, (gpointer) chat);
1641 nm_send_create_conference(user, conference, _createconf_resp_send_invite, user_record);
1642 nm_release_conference(conference);
1646 const char *
1647 _get_conference_name(int id)
1649 static char *name = NULL;
1651 g_free(name);
1653 name = g_strdup_printf(_("GroupWise Conference %d"), id);
1655 return name;
1658 static void
1659 _show_privacy_locked_error(PurpleConnection *gc, NMUser *user)
1661 char *err;
1663 err = g_strdup_printf(_("Unable to change server side privacy settings (%s)."),
1664 nm_error_to_string(NMERR_ADMIN_LOCKED));
1665 purple_notify_error(gc, NULL, err, NULL,
1666 purple_request_cpar_from_connection(gc));
1667 g_free(err);
1670 /*******************************************************************************
1671 * Connect and recv callbacks
1672 ******************************************************************************/
1674 static void
1675 novell_ssl_connect_error(PurpleSslConnection * gsc,
1676 PurpleSslErrorType error, gpointer data)
1678 PurpleConnection *gc;
1679 NMUser *user;
1681 gc = data;
1682 user = purple_connection_get_protocol_data(gc);
1683 user->conn->ssl_conn->data = NULL;
1685 purple_connection_ssl_error (gc, error);
1688 static void
1689 novell_ssl_recv_cb(gpointer data, PurpleSslConnection * gsc,
1690 PurpleInputCondition condition)
1692 PurpleConnection *gc = data;
1693 NMUser *user;
1694 NMERR_T rc;
1696 if (gc == NULL)
1697 return;
1699 user = purple_connection_get_protocol_data(gc);
1700 if (user == NULL)
1701 return;
1703 rc = nm_process_new_data(user);
1704 if (rc != NM_OK) {
1706 if (_is_disconnect_error(rc)) {
1708 purple_connection_error(gc,
1709 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
1710 _("Error communicating with server. Closing connection."));
1711 } else {
1712 purple_debug(PURPLE_DEBUG_INFO, "novell",
1713 "Error processing event or response (%d).\n", rc);
1718 static void
1719 novell_ssl_connected_cb(gpointer data, PurpleSslConnection * gsc,
1720 PurpleInputCondition cond)
1722 PurpleConnection *gc = data;
1723 NMUser *user;
1724 NMConn *conn;
1725 NMERR_T rc = 0;
1726 const char *pwd = NULL;
1727 const char *my_addr = NULL;
1728 char *ua = NULL;
1730 if (gc == NULL || gsc == NULL)
1731 return;
1733 user = purple_connection_get_protocol_data(gc);
1734 if ((user == NULL) || (conn = user->conn) == NULL)
1735 return;
1737 purple_connection_update_progress(gc, _("Authenticating..."),
1738 2, NOVELL_CONNECT_STEPS);
1740 my_addr = purple_network_get_my_ip(gsc->fd);
1741 pwd = purple_connection_get_password(gc);
1742 ua = _user_agent_string();
1744 rc = nm_send_login(user, pwd, my_addr, ua, _login_resp_cb, NULL);
1745 if (rc == NM_OK) {
1746 conn->connected = TRUE;
1747 purple_ssl_input_add(gsc, novell_ssl_recv_cb, gc);
1748 } else {
1749 purple_connection_error(gc,
1750 PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
1751 _("Unable to connect"));
1754 purple_connection_update_progress(gc, _("Waiting for response..."),
1755 3, NOVELL_CONNECT_STEPS);
1757 g_free(ua);
1760 /*******************************************************************************
1761 * Event callback and event handlers
1762 ******************************************************************************/
1764 static void
1765 _evt_receive_message(NMUser * user, NMEvent * event)
1767 NMUserRecord *user_record = NULL;
1768 NMContact *contact = NULL;
1769 PurpleIMConversation *im;
1770 NMConference *conference;
1771 PurpleMessageFlags flags;
1772 char *text = NULL;
1774 text = g_markup_escape_text(nm_event_get_text(event), -1);
1776 conference = nm_event_get_conference(event);
1777 if (conference) {
1779 PurpleChatConversation *chat = nm_conference_get_data(conference);
1781 /* Is this a single person 'conversation' or a conference? */
1782 if (chat == NULL && nm_conference_get_participant_count(conference) == 1) {
1784 user_record = nm_find_user_record(user, nm_event_get_source(event));
1785 if (user_record) {
1787 flags = 0;
1788 if (nm_event_get_type(event) == NMEVT_RECEIVE_AUTOREPLY)
1789 flags |= PURPLE_MESSAGE_AUTO_RESP;
1791 purple_serv_got_im(purple_account_get_connection(user->client_data),
1792 nm_user_record_get_display_id(user_record),
1793 text, flags,
1794 nm_event_get_gmt(event));
1796 im = purple_conversations_find_im_with_account(
1797 nm_user_record_get_display_id(user_record),
1798 (PurpleAccount *) user->client_data);
1799 if (im) {
1801 contact = nm_find_contact(user, nm_event_get_source(event));
1802 if (contact) {
1804 purple_conversation_set_title(PURPLE_CONVERSATION(im),
1805 nm_contact_get_display_name(contact));
1808 } else {
1810 const char *name =
1811 nm_user_record_get_full_name(user_record);
1813 if (name == NULL)
1814 name = nm_user_record_get_userid(user_record);
1816 purple_conversation_set_title(PURPLE_CONVERSATION(im), name);
1821 } else {
1822 /* this should not happen, see the event code.
1823 * the event code will get the contact details from
1824 * the server if it does not have them before calling
1825 * the event callback.
1829 } else if (chat) {
1831 /* get the contact for send if we have one */
1832 NMContact *contact = nm_find_contact(user,
1833 nm_event_get_source(event));
1835 /* get the user record for the sender */
1836 user_record = nm_find_user_record(user, nm_event_get_source(event));
1837 if (user_record) {
1838 const char *name = nm_contact_get_display_name(contact);
1840 if (name == NULL) {
1841 name = nm_user_record_get_full_name(user_record);
1842 if (name == NULL)
1843 name = nm_user_record_get_display_id(user_record);
1846 purple_serv_got_chat_in(purple_account_get_connection(user->client_data),
1847 purple_chat_conversation_get_id(chat),
1848 name, PURPLE_MESSAGE_RECV, text, nm_event_get_gmt(event));
1853 g_free(text);
1856 static void
1857 _evt_conference_left(NMUser * user, NMEvent * event)
1859 PurpleChatConversation *chat;
1860 NMConference *conference;
1862 conference = nm_event_get_conference(event);
1863 if (conference) {
1864 chat = nm_conference_get_data(conference);
1865 if (chat) {
1866 NMUserRecord *ur = nm_find_user_record(user,
1867 nm_event_get_source(event));
1869 if (ur)
1870 purple_chat_conversation_remove_user(chat,
1871 nm_user_record_get_display_id(ur),
1872 NULL);
1877 static void
1878 _evt_conference_invite_notify(NMUser * user, NMEvent * event)
1880 PurpleConversation *gconv;
1881 NMConference *conference;
1882 NMUserRecord *user_record = NULL;
1883 char *str = NULL;
1885 user_record = nm_find_user_record(user, nm_event_get_source(event));
1886 conference = nm_event_get_conference(event);
1887 if (user_record && conference) {
1888 gconv = nm_conference_get_data(conference);
1889 str = g_strdup_printf(_("%s has been invited to this conversation."),
1890 nm_user_record_get_display_id(user_record));
1891 purple_conversation_write_system_message(gconv, str, 0);
1892 g_free(str);
1896 static void
1897 _evt_conference_invite(NMUser * user, NMEvent * event)
1899 NMUserRecord *ur;
1900 PurpleConnection *gc;
1901 GSList *parms = NULL;
1902 const char *title = NULL;
1903 const char *secondary = NULL;
1904 const char *name = NULL;
1905 char *primary = NULL;
1906 time_t gmt;
1908 ur = nm_find_user_record(user, nm_event_get_source(event));
1909 if (ur)
1910 name = nm_user_record_get_full_name(ur);
1912 if (name == NULL)
1913 name = nm_event_get_source(event);
1915 gmt = nm_event_get_gmt(event);
1916 title = _("Invitation to Conversation");
1917 primary = g_strdup_printf(_("Invitation from: %s\n\nSent: %s"),
1918 name, purple_date_format_full(localtime(&gmt)));
1919 secondary = _("Would you like to join the conversation?");
1921 /* Set up parms list for the callbacks
1922 * We need to send the NMUser object and
1923 * the NMConference object to the callbacks
1925 parms = NULL;
1926 parms = g_slist_append(parms, user);
1927 parms = g_slist_append(parms, nm_event_get_conference(event));
1929 /* Prompt the user */
1930 /* TODO: Would it be better to use purple_serv_got_chat_invite() here? */
1931 gc = purple_account_get_connection(user->client_data);
1932 purple_request_action(gc, title, primary, secondary,
1933 PURPLE_DEFAULT_ACTION_NONE,
1934 purple_request_cpar_from_connection(gc),
1935 parms, 2,
1936 _("Yes"), G_CALLBACK(_join_conference_cb),
1937 _("No"), G_CALLBACK(_reject_conference_cb));
1939 g_free(primary);
1943 static void
1944 _evt_conference_joined(NMUser * user, NMEvent * event)
1946 PurpleChatConversation *chat = NULL;
1947 PurpleConnection *gc;
1948 NMConference *conference = NULL;
1949 NMUserRecord *ur = NULL;
1950 const char *name;
1951 const char *conf_name;
1953 gc = purple_account_get_connection(user->client_data);
1954 if (gc == NULL)
1955 return;
1957 conference = nm_event_get_conference(event);
1958 if (conference) {
1959 chat = nm_conference_get_data(conference);
1960 if (nm_conference_get_participant_count(conference) == 2 && chat == NULL) {
1961 ur = nm_conference_get_participant(conference, 0);
1962 if (ur) {
1963 conf_name = _get_conference_name(++user->conference_count);
1964 chat =
1965 purple_serv_got_joined_chat(gc, user->conference_count, conf_name);
1966 if (chat) {
1968 nm_conference_set_data(conference, (gpointer) chat);
1970 name = nm_user_record_get_display_id(ur);
1971 purple_chat_conversation_add_user(chat, name, NULL,
1972 PURPLE_CHAT_USER_NONE, TRUE);
1978 if (chat != NULL) {
1979 ur = nm_find_user_record(user, nm_event_get_source(event));
1980 if (ur) {
1981 name = nm_user_record_get_display_id(ur);
1982 if (!purple_chat_conversation_has_user(chat, name)) {
1983 purple_chat_conversation_add_user(chat, name, NULL,
1984 PURPLE_CHAT_USER_NONE, TRUE);
1991 static void
1992 _evt_status_change(NMUser * user, NMEvent * event)
1994 PurpleBuddy *buddy = NULL;
1995 GSList *buddies;
1996 GSList *bnode;
1997 NMUserRecord *user_record;
1998 const char *display_id;
1999 int status;
2001 user_record = nm_event_get_user_record(event);
2002 if (user_record) {
2004 /* Retrieve new status */
2005 status = nm_user_record_get_status(user_record);
2007 /* Update status for buddy in all folders */
2008 display_id = nm_user_record_get_display_id(user_record);
2009 buddies = purple_blist_find_buddies(user->client_data, display_id);
2010 for (bnode = buddies; bnode; bnode = bnode->next) {
2011 buddy = (PurpleBuddy *) bnode->data;
2012 if (buddy) {
2013 _update_buddy_status(user, buddy, status, nm_event_get_gmt(event));
2017 g_slist_free(buddies);
2022 static void
2023 _evt_user_disconnect(NMUser * user, NMEvent * event)
2025 PurpleConnection *gc;
2026 PurpleAccount *account = user->client_data;
2028 gc = purple_account_get_connection(account);
2029 if (gc)
2031 if (!purple_account_get_remember_password(account))
2032 purple_account_set_password(account, NULL, NULL, NULL);
2033 purple_connection_error(gc,
2034 PURPLE_CONNECTION_ERROR_NAME_IN_USE,
2035 _("You have signed on from another location"));
2039 static void
2040 _evt_user_typing(NMUser * user, NMEvent * event)
2042 PurpleConnection *gc;
2043 NMUserRecord *user_record = NULL;
2045 gc = purple_account_get_connection((PurpleAccount *) user->client_data);
2046 if (gc) {
2047 user_record = nm_find_user_record(user, nm_event_get_source(event));
2048 if (user_record) {
2049 purple_serv_got_typing(gc, nm_user_record_get_display_id(user_record),
2050 30, PURPLE_IM_TYPING);
2055 static void
2056 _evt_user_not_typing(NMUser * user, NMEvent * event)
2058 PurpleConnection *gc;
2059 NMUserRecord *user_record;
2061 gc = purple_account_get_connection((PurpleAccount *) user->client_data);
2062 if (gc) {
2063 user_record = nm_find_user_record(user, nm_event_get_source(event));
2064 if (user_record) {
2065 purple_serv_got_typing_stopped(gc,
2066 nm_user_record_get_display_id(user_record));
2071 static void
2072 _evt_undeliverable_status(NMUser * user, NMEvent * event)
2074 NMUserRecord *ur;
2075 PurpleConversation *gconv;
2076 char *str;
2078 ur = nm_find_user_record(user, nm_event_get_source(event));
2079 if (ur) {
2080 /* XXX - Should this be PURPLE_CONV_TYPE_IM? */
2081 gconv =
2082 purple_conversations_find_with_account(nm_user_record_get_display_id(ur),
2083 user->client_data);
2084 if (gconv) {
2085 const char *name = nm_user_record_get_full_name(ur);
2087 if (name == NULL) {
2088 name = nm_user_record_get_display_id(ur);
2090 str = g_strdup_printf(_("%s appears to be offline and did not receive"
2091 " the message that you just sent."), name);
2092 purple_conversation_write_system_message(gconv, str, 0);
2093 g_free(str);
2098 static void
2099 _event_callback(NMUser * user, NMEvent * event)
2101 if (user == NULL || event == NULL)
2102 return;
2104 switch (nm_event_get_type(event)) {
2105 case NMEVT_STATUS_CHANGE:
2106 _evt_status_change(user, event);
2107 break;
2108 case NMEVT_RECEIVE_AUTOREPLY:
2109 case NMEVT_RECEIVE_MESSAGE:
2110 _evt_receive_message(user, event);
2111 break;
2112 case NMEVT_USER_DISCONNECT:
2113 _evt_user_disconnect(user, event);
2114 break;
2115 case NMEVT_USER_TYPING:
2116 _evt_user_typing(user, event);
2117 break;
2118 case NMEVT_USER_NOT_TYPING:
2119 _evt_user_not_typing(user, event);
2120 break;
2121 case NMEVT_SERVER_DISCONNECT:
2122 /* Nothing to do? */
2123 break;
2124 case NMEVT_INVALID_RECIPIENT:
2125 break;
2126 case NMEVT_UNDELIVERABLE_STATUS:
2127 _evt_undeliverable_status(user, event);
2128 break;
2129 case NMEVT_CONFERENCE_INVITE_NOTIFY:
2130 /* Someone else has been invited to join a
2131 * conference that we are currently a part of
2133 _evt_conference_invite_notify(user, event);
2134 break;
2135 case NMEVT_CONFERENCE_INVITE:
2136 /* We have been invited to join a conference */
2137 _evt_conference_invite(user, event);
2138 break;
2139 case NMEVT_CONFERENCE_JOINED:
2140 /* Some one has joined a conference that we
2141 * are a part of
2143 _evt_conference_joined(user, event);
2144 break;
2145 case NMEVT_CONFERENCE_LEFT:
2146 /* Someone else has left a conference that we
2147 * are currently a part of
2149 _evt_conference_left(user, event);
2150 break;
2151 default:
2152 purple_debug(PURPLE_DEBUG_INFO, "novell",
2153 "_event_callback(): unhandled event, %d\n",
2154 nm_event_get_type(event));
2155 break;
2159 /*******************************************************************************
2160 * Protocol Ops
2161 ******************************************************************************/
2163 static void
2164 novell_login(PurpleAccount * account)
2166 PurpleConnection *gc;
2167 NMUser *user = NULL;
2168 const char *server;
2169 const char *name;
2170 int port;
2172 if (account == NULL)
2173 return;
2175 gc = purple_account_get_connection(account);
2176 if (gc == NULL)
2177 return;
2179 purple_connection_set_flags(gc, PURPLE_CONNECTION_FLAG_NO_IMAGES);
2181 server = purple_account_get_string(account, "server", NULL);
2182 if (server == NULL || *server == '\0') {
2184 /* TODO: Would be nice to prompt if not set!
2185 * purple_request_fields(gc, _("Server Address"),...);
2188 /* ...but for now just error out with a nice message. */
2189 purple_connection_error(gc,
2190 PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
2191 _("Unable to connect to server. Please enter the "
2192 "address of the server to which you wish to connect."));
2193 return;
2196 port = purple_account_get_int(account, "port", DEFAULT_PORT);
2197 name = purple_account_get_username(account);
2199 user = nm_initialize_user(name, server, port, account, _event_callback);
2200 if (user && user->conn) {
2201 /* save user */
2202 purple_connection_set_protocol_data(gc, user);
2204 /* connect to the server */
2205 purple_connection_update_progress(gc, _("Connecting"),
2206 1, NOVELL_CONNECT_STEPS);
2208 user->conn->use_ssl = TRUE;
2210 user->conn->ssl_conn = g_new0(NMSSLConn, 1);
2211 user->conn->ssl_conn->read = (nm_ssl_read_cb) purple_ssl_read;
2212 user->conn->ssl_conn->write = (nm_ssl_write_cb) purple_ssl_write;
2214 user->conn->ssl_conn->data = purple_ssl_connect(user->client_data,
2215 user->conn->addr, user->conn->port,
2216 novell_ssl_connected_cb, novell_ssl_connect_error, gc);
2217 if (user->conn->ssl_conn->data == NULL) {
2218 purple_connection_error(gc,
2219 PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
2220 _("SSL support unavailable"));
2225 static void
2226 novell_close(PurpleConnection * gc)
2228 NMUser *user;
2229 NMConn *conn;
2231 if (gc == NULL)
2232 return;
2234 user = purple_connection_get_protocol_data(gc);
2235 if (user) {
2236 conn = user->conn;
2237 if (conn && conn->ssl_conn) {
2238 purple_ssl_close(user->conn->ssl_conn->data);
2240 nm_deinitialize_user(user);
2242 purple_connection_set_protocol_data(gc, NULL);
2245 static int
2246 novell_send_im(PurpleConnection *gc, PurpleMessage *msg)
2248 NMUserRecord *user_record = NULL;
2249 NMConference *conf = NULL;
2250 NMMessage *message;
2251 NMUser *user;
2252 const char *dn = NULL;
2253 char *plain;
2254 gboolean done = TRUE, created_conf = FALSE;
2255 NMERR_T rc = NM_OK;
2256 const gchar *name = purple_message_get_recipient(msg);
2258 if (gc == NULL || name == NULL || purple_message_is_empty(msg))
2259 return 0;
2261 user = purple_connection_get_protocol_data(gc);
2262 if (user == NULL)
2263 return 0;
2265 /* Create a new message */
2266 plain = purple_unescape_html(purple_message_get_contents(msg));
2267 message = nm_create_message(plain);
2268 g_free(plain);
2270 /* Need to get the DN for the buddy so we can look up the convo */
2271 dn = nm_lookup_dn(user, name);
2273 /* Do we already know about the sender? */
2274 user_record = nm_find_user_record(user, dn);
2275 if (user_record) {
2277 /* Do we already have an instantiated conference? */
2278 conf = nm_find_conversation(user, dn);
2279 if (conf == NULL) {
2281 /* If not, create a blank conference */
2282 conf = nm_create_conference(NULL);
2283 created_conf = TRUE;
2285 nm_conference_add_participant(conf, user_record);
2288 nm_message_set_conference(message, conf);
2290 /* Make sure conference is instantiated */
2291 if (!nm_conference_is_instantiated(conf)) {
2293 /* It is not, so send the createconf. We will
2294 * have to finish sending the message when we
2295 * get the response with the new conference guid.
2297 rc = nm_send_create_conference(user, conf, _createconf_resp_send_msg, message);
2298 _check_for_disconnect(user, rc);
2300 done = FALSE;
2303 } else {
2305 /* If we don't have details for the user, then we don't have
2306 * a conference yet. So create one and send the getdetails
2307 * to the server. We will have to finish sending the message
2308 * when we get the response from the server.
2310 conf = nm_create_conference(NULL);
2311 created_conf = TRUE;
2313 nm_message_set_conference(message, conf);
2315 rc = nm_send_get_details(user, name, _get_details_resp_send_msg, message);
2316 _check_for_disconnect(user, rc);
2318 done = FALSE;
2321 if (done) {
2323 /* Did we find everything we needed? */
2324 rc = nm_send_message(user, message, _send_message_resp_cb);
2325 _check_for_disconnect(user, rc);
2327 nm_release_message(message);
2330 if (created_conf && conf)
2331 nm_release_conference(conf);
2333 return 1;
2336 static unsigned int
2337 novell_send_typing(PurpleConnection * gc, const char *name, PurpleIMTypingState state)
2339 NMConference *conf = NULL;
2340 NMUser *user;
2341 const char *dn = NULL;
2342 NMERR_T rc = NM_OK;
2344 if (gc == NULL || name == NULL)
2345 return 0;
2347 user = purple_connection_get_protocol_data(gc);
2348 if (user == NULL)
2349 return 0;
2351 /* Need to get the DN for the buddy so we can look up the convo */
2352 dn = nm_lookup_dn(user, name);
2353 if (dn) {
2355 /* Now find the conference in our list */
2356 conf = nm_find_conversation(user, dn);
2357 if (conf) {
2359 rc = nm_send_typing(user, conf,
2360 ((state == PURPLE_IM_TYPING) ? TRUE : FALSE), NULL);
2361 _check_for_disconnect(user, rc);
2367 return 0;
2370 static void
2371 novell_convo_closed(PurpleConnection * gc, const char *who)
2373 NMUser *user;
2374 NMConference *conf;
2375 const char *dn;
2376 NMERR_T rc = NM_OK;
2378 if (gc == NULL || who == NULL)
2379 return;
2381 user = purple_connection_get_protocol_data(gc);
2382 if (user && (dn = nm_lookup_dn(user, who))) {
2383 conf = nm_find_conversation(user, dn);
2384 if (conf) {
2385 rc = nm_send_leave_conference(user, conf, NULL, NULL);
2386 _check_for_disconnect(user, rc);
2391 static void
2392 novell_chat_leave(PurpleConnection * gc, int id)
2394 NMConference *conference;
2395 NMUser *user;
2396 PurpleChatConversation *chat;
2397 GSList *cnode;
2398 NMERR_T rc = NM_OK;
2400 if (gc == NULL)
2401 return;
2403 user = purple_connection_get_protocol_data(gc);
2404 if (user == NULL)
2405 return;
2407 for (cnode = user->conferences; cnode != NULL; cnode = cnode->next) {
2408 conference = cnode->data;
2409 if (conference && (chat = nm_conference_get_data(conference))) {
2410 if (purple_chat_conversation_get_id(chat) == id) {
2411 rc = nm_send_leave_conference(user, conference, NULL, NULL);
2412 _check_for_disconnect(user, rc);
2413 break;
2418 purple_serv_got_chat_left(gc, id);
2421 static void
2422 novell_chat_invite(PurpleConnection *gc, int id,
2423 const char *message, const char *who)
2425 NMConference *conference;
2426 NMUser *user;
2427 PurpleChatConversation *chat;
2428 GSList *cnode;
2429 NMERR_T rc = NM_OK;
2430 NMUserRecord *user_record = NULL;
2432 if (gc == NULL)
2433 return;
2435 user = purple_connection_get_protocol_data(gc);
2436 if (user == NULL)
2437 return;
2439 user_record = nm_find_user_record(user, who);
2440 if (user_record == NULL) {
2441 rc = nm_send_get_details(user, who, _get_details_resp_send_invite, GINT_TO_POINTER(id));
2442 _check_for_disconnect(user, rc);
2443 return;
2446 for (cnode = user->conferences; cnode != NULL; cnode = cnode->next) {
2447 conference = cnode->data;
2448 if (conference && (chat = nm_conference_get_data(conference))) {
2449 if (purple_chat_conversation_get_id(chat) == id) {
2450 rc = nm_send_conference_invite(user, conference, user_record,
2451 message, _sendinvite_resp_cb, NULL);
2452 _check_for_disconnect(user, rc);
2453 break;
2459 static int
2460 novell_chat_send(PurpleConnection * gc, int id, PurpleMessage *msg)
2462 NMConference *conference;
2463 PurpleChatConversation *chat;
2464 GSList *cnode;
2465 NMMessage *message;
2466 NMUser *user;
2467 NMERR_T rc = NM_OK;
2468 const char *name;
2469 char *str, *plain;
2471 if (gc == NULL || purple_message_is_empty(msg))
2472 return -1;
2474 user = purple_connection_get_protocol_data(gc);
2475 if (user == NULL)
2476 return -1;
2478 plain = purple_unescape_html(purple_message_get_contents(msg));
2479 message = nm_create_message(plain);
2480 g_free(plain);
2482 for (cnode = user->conferences; cnode != NULL; cnode = cnode->next) {
2483 conference = cnode->data;
2484 if (conference && (chat = nm_conference_get_data(conference))) {
2485 if (purple_chat_conversation_get_id(chat) == id) {
2487 nm_message_set_conference(message, conference);
2489 /* check to see if the conference is instatiated yet */
2490 if (!nm_conference_is_instantiated(conference)) {
2491 nm_message_add_ref(message);
2492 nm_send_create_conference(user, conference, _createconf_resp_send_msg, message);
2493 } else {
2494 rc = nm_send_message(user, message, _send_message_resp_cb);
2497 nm_release_message(message);
2499 if (!_check_for_disconnect(user, rc)) {
2501 /* Use the account alias if it is set */
2502 name = purple_account_get_private_alias(user->client_data);
2503 if (name == NULL || *name == '\0') {
2505 /* If there is no account alias, try full name */
2506 name = nm_user_record_get_full_name(user->user_record);
2507 if (name == NULL || *name == '\0') {
2509 /* Fall back to the username that we are signed in with */
2510 name = purple_account_get_username(user->client_data);
2514 purple_serv_got_chat_in(gc, id, name,
2515 purple_message_get_flags(msg),
2516 purple_message_get_contents(msg), time(NULL));
2517 return 0;
2518 } else
2519 return -1;
2526 /* The conference was not found, must be closed */
2527 chat = purple_conversations_find_chat(gc, id);
2528 if (chat) {
2529 str = g_strdup(_("This conference has been closed."
2530 " No more messages can be sent."));
2531 purple_conversation_write_system_message(PURPLE_CONVERSATION(chat), str, 0);
2532 g_free(str);
2535 if (message)
2536 nm_release_message(message);
2538 return -1;
2541 static void
2542 novell_add_buddy(PurpleConnection * gc, PurpleBuddy *buddy, PurpleGroup * group, const char *message)
2544 NMFolder *folder = NULL;
2545 NMContact *contact;
2546 NMUser *user;
2547 NMERR_T rc = NM_OK;
2548 const char *alias, *gname, *bname;
2550 if (gc == NULL || buddy == NULL || group == NULL)
2551 return;
2553 user = (NMUser *) purple_connection_get_protocol_data(gc);
2554 if (user == NULL)
2555 return;
2557 /* If we haven't synched the contact list yet, ignore
2558 * the add_buddy calls. Server side list is the master.
2560 if (!user->clist_synched)
2561 return;
2563 /* Don't re-add a buddy that is already on our contact list */
2564 if (nm_find_user_record(user, purple_buddy_get_name(buddy)) != NULL)
2565 return;
2567 contact = nm_create_contact();
2568 nm_contact_set_dn(contact, purple_buddy_get_name(buddy));
2570 /* Remove the PurpleBuddy (we will add it back after adding it
2571 * to the server side list). Save the alias if there is one.
2573 alias = purple_buddy_get_alias(buddy);
2574 bname = purple_buddy_get_name(buddy);
2575 if (alias && !purple_strequal(alias, bname))
2576 nm_contact_set_display_name(contact, alias);
2578 purple_blist_remove_buddy(buddy);
2579 buddy = NULL;
2581 gname = purple_group_get_name(group);
2582 if (purple_strequal(gname, NM_ROOT_FOLDER_NAME)) {
2583 gname = "";
2586 folder = nm_find_folder(user, gname);
2587 if (folder) {
2589 /* We have everything that we need, so send the createcontact */
2590 rc = nm_send_create_contact(user, folder, contact,
2591 _create_contact_resp_cb, contact);
2593 } else {
2595 /* Need to create the folder before we can add the contact */
2596 rc = nm_send_create_folder(user, gname,
2597 _create_folder_resp_add_contact, contact);
2600 _check_for_disconnect(user, rc);
2604 static void
2605 novell_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group)
2607 NMContact *contact;
2608 NMFolder *folder;
2609 NMUser *user;
2610 const char *dn, *gname;
2611 NMERR_T rc = NM_OK;
2613 if (gc == NULL || buddy == NULL || group == NULL)
2614 return;
2616 user = purple_connection_get_protocol_data(gc);
2617 if (user && (dn = nm_lookup_dn(user, purple_buddy_get_name(buddy)))) {
2618 gname = purple_group_get_name(group);
2619 if (purple_strequal(gname, NM_ROOT_FOLDER_NAME)) {
2620 gname = "";
2622 folder = nm_find_folder(user, gname);
2623 if (folder) {
2624 contact = nm_folder_find_contact(folder, dn);
2625 if (contact) {
2627 /* Remove the buddy from the contact */
2628 nm_contact_set_data(contact, NULL);
2630 /* Tell the server to remove the contact */
2631 rc = nm_send_remove_contact(user, folder, contact,
2632 _remove_contact_resp_cb, NULL);
2633 _check_for_disconnect(user, rc);
2639 static void
2640 novell_remove_group(PurpleConnection * gc, PurpleGroup *group)
2642 NMUser *user;
2643 NMERR_T rc = NM_OK;
2645 if (gc == NULL || group == NULL)
2646 return;
2648 user = purple_connection_get_protocol_data(gc);
2649 if (user) {
2650 NMFolder *folder = nm_find_folder(user, purple_group_get_name(group));
2652 if (folder) {
2653 rc = nm_send_remove_folder(user, folder,
2654 _remove_folder_resp_cb, NULL);
2655 _check_for_disconnect(user, rc);
2660 static void
2661 novell_alias_buddy(PurpleConnection * gc, const char *name, const char *alias)
2663 NMContact *contact;
2664 NMUser *user;
2665 GList *contacts = NULL;
2666 GList *cnode = NULL;
2667 const char *dn = NULL, *fname = NULL;
2668 NMERR_T rc = NM_OK;
2670 if (gc == NULL || name == NULL || alias == NULL)
2671 return;
2673 user = purple_connection_get_protocol_data(gc);
2674 if (user && (dn = nm_lookup_dn(user, name))) {
2676 /* Alias all of instances of the contact */
2677 contacts = nm_find_contacts(user, dn);
2678 for (cnode = contacts; cnode != NULL; cnode = cnode->next) {
2679 contact = (NMContact *) cnode->data;
2680 if (contact) {
2681 PurpleGroup *group = NULL;
2682 PurpleBuddy *buddy;
2683 NMFolder *folder;
2685 /* Alias the Purple buddy? */
2686 folder = nm_find_folder_by_id(user,
2687 nm_contact_get_parent_id(contact));
2688 if (folder) {
2689 fname = nm_folder_get_name(folder);
2690 if (*fname == '\0') {
2691 fname = NM_ROOT_FOLDER_NAME;
2693 group = purple_blist_find_group(fname);
2696 if (group) {
2697 const char *balias;
2698 buddy = purple_blist_find_buddy_in_group(user->client_data,
2699 name, group);
2700 balias = buddy ? purple_buddy_get_local_alias(buddy) : NULL;
2701 if (balias && !purple_strequal(balias, alias))
2702 purple_buddy_set_local_alias(buddy, alias);
2705 /* Tell the server to alias the contact */
2706 rc = nm_send_rename_contact(user, contact, alias,
2707 _rename_contact_resp_cb, NULL);
2708 _check_for_disconnect(user, rc);
2711 if (contacts)
2712 g_list_free(contacts);
2716 static void
2717 novell_group_buddy(PurpleConnection * gc,
2718 const char *name, const char *old_group_name,
2719 const char *new_group_name)
2721 NMFolder *old_folder;
2722 NMFolder *new_folder;
2723 NMContact *contact;
2724 NMUser *user;
2725 const char *dn;
2726 NMERR_T rc = NM_OK;
2728 if (gc == NULL || name == NULL ||
2729 old_group_name == NULL || new_group_name == NULL)
2730 return;
2732 user = purple_connection_get_protocol_data(gc);
2733 if (user && (dn = nm_lookup_dn(user, name))) {
2735 /* Find the old folder */
2736 if (purple_strequal(old_group_name, NM_ROOT_FOLDER_NAME)) {
2737 old_folder = nm_get_root_folder(user);
2738 if (nm_folder_find_contact(old_folder, dn) == NULL)
2739 old_folder = nm_find_folder(user, old_group_name);
2740 } else {
2741 old_folder = nm_find_folder(user, old_group_name);
2744 if (old_folder && (contact = nm_folder_find_contact(old_folder, dn))) {
2746 /* Find the new folder */
2747 new_folder = nm_find_folder(user, new_group_name);
2748 if (new_folder == NULL) {
2749 if (purple_strequal(new_group_name, NM_ROOT_FOLDER_NAME))
2750 new_folder = nm_get_root_folder(user);
2753 if (new_folder) {
2755 /* Tell the server to move the contact to the new folder */
2756 rc = nm_send_move_contact(user, contact, new_folder,
2757 _move_contact_resp_cb, NULL);
2759 } else {
2761 nm_contact_add_ref(contact);
2763 /* Remove the old contact first */
2764 nm_send_remove_contact(user, old_folder, contact,
2765 _remove_contact_resp_cb, NULL);
2767 /* New folder does not exist yet, so create it */
2768 rc = nm_send_create_folder(user, new_group_name,
2769 _create_folder_resp_move_contact,
2770 contact);
2773 _check_for_disconnect(user, rc);
2778 static void
2779 novell_rename_group(PurpleConnection * gc, const char *old_name,
2780 PurpleGroup *group, GList *moved_buddies)
2782 NMERR_T rc = NM_OK;
2783 NMFolder *folder;
2784 NMUser *user;
2786 if (gc == NULL || old_name == NULL || group == NULL || moved_buddies == NULL) {
2787 return;
2790 user = purple_connection_get_protocol_data(gc);
2791 if (user) {
2792 const char *gname = purple_group_get_name(group);
2793 /* Does new folder exist already? */
2794 if (nm_find_folder(user, gname)) {
2795 /* purple_group_set_name() adds the buddies
2796 * to the new group and removes the old group...
2797 * so there is nothing more to do here.
2799 return;
2802 if (purple_strequal(old_name, NM_ROOT_FOLDER_NAME)) {
2803 /* Can't rename the root folder ... need to revisit this */
2804 return;
2807 folder = nm_find_folder(user, old_name);
2808 if (folder) {
2809 rc = nm_send_rename_folder(user, folder, gname,
2810 _rename_folder_resp_cb, NULL);
2811 _check_for_disconnect(user, rc);
2816 static const char *
2817 novell_list_icon(PurpleAccount * account, PurpleBuddy * buddy)
2819 return "novell";
2822 static void
2823 novell_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * user_info, gboolean full)
2825 NMUserRecord *user_record = NULL;
2826 PurpleConnection *gc;
2827 NMUser *user;
2828 int status = 0;
2829 const char *status_str = NULL;
2830 const char *text = NULL;
2832 if (buddy == NULL)
2833 return;
2835 gc = purple_account_get_connection(purple_buddy_get_account(buddy));
2836 if (gc == NULL || (user = purple_connection_get_protocol_data(gc)) == NULL)
2837 return;
2839 if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
2840 user_record = nm_find_user_record(user, purple_buddy_get_name(buddy));
2841 if (user_record) {
2842 status = nm_user_record_get_status(user_record);
2843 text = nm_user_record_get_status_text(user_record);
2844 /* No custom text, so default it ... */
2845 switch (status) {
2846 case NM_STATUS_AVAILABLE:
2847 status_str = _("Available");
2848 break;
2849 case NM_STATUS_AWAY:
2850 status_str = _("Away");
2851 break;
2852 case NM_STATUS_BUSY:
2853 status_str = _("Busy");
2854 break;
2855 case NM_STATUS_AWAY_IDLE:
2856 status_str = _("Idle");
2857 break;
2858 case NM_STATUS_OFFLINE:
2859 status_str = _("Offline");
2860 break;
2861 default:
2862 status_str = _("Unknown");
2863 break;
2866 purple_notify_user_info_add_pair_plaintext(user_info, _("Status"), status_str);
2868 if (text) {
2869 /* TODO: Check whether it's correct to call add_pair_html,
2870 or if we should be using add_pair_plaintext */
2871 purple_notify_user_info_add_pair_html(user_info, _("Message"), text);
2877 static void
2878 novell_set_idle(PurpleConnection * gc, int time)
2880 NMUser *user;
2881 NMERR_T rc = NM_OK;
2882 const char *id = NULL;
2883 PurpleStatus *status = NULL;
2885 if (gc == NULL)
2886 return;
2888 user = purple_connection_get_protocol_data(gc);
2889 if (user == NULL)
2890 return;
2892 status = purple_account_get_active_status(purple_connection_get_account(gc));
2893 id = purple_status_get_id(status);
2895 /* Only go idle if active status is available */
2896 if (purple_strequal(id, NOVELL_STATUS_TYPE_AVAILABLE)) {
2897 if (time > 0) {
2898 rc = nm_send_set_status(user, NM_STATUS_AWAY_IDLE, NULL, NULL, NULL, NULL);
2899 } else {
2900 rc = nm_send_set_status(user, NM_STATUS_AVAILABLE, NULL, NULL, NULL, NULL);
2904 _check_for_disconnect(user, rc);
2907 static void
2908 novell_get_info(PurpleConnection * gc, const char *name)
2910 NMUserRecord *user_record;
2911 NMUser *user;
2912 NMERR_T rc;
2914 if (gc == NULL || name == NULL)
2915 return;
2917 user = purple_connection_get_protocol_data(gc);
2918 if (user) {
2920 user_record = nm_find_user_record(user, name);
2921 if (user_record) {
2922 _show_info(gc, user_record, g_strdup(name));
2924 } else {
2925 rc = nm_send_get_details(user, name,
2926 _get_details_resp_show_info, g_strdup(name));
2928 _check_for_disconnect(user, rc);
2935 static char *
2936 novell_status_text(PurpleBuddy * buddy)
2938 const char *text = NULL;
2939 const char *dn = NULL;
2940 PurpleAccount *account;
2942 account = buddy ? purple_buddy_get_account(buddy) : NULL;
2943 if (buddy && account) {
2944 PurpleConnection *gc = purple_account_get_connection(account);
2946 if (gc) {
2947 NMUser *user = purple_connection_get_protocol_data(gc);
2949 if (user) {
2950 dn = nm_lookup_dn(user, purple_buddy_get_name(buddy));
2951 if (dn) {
2952 NMUserRecord *user_record = nm_find_user_record(user, dn);
2954 if (user_record) {
2955 text = nm_user_record_get_status_text(user_record);
2956 if (text)
2957 return g_strdup(text);
2964 return NULL;
2967 static GList *
2968 novell_status_types(PurpleAccount *account)
2970 GList *status_types = NULL;
2971 PurpleStatusType *type;
2973 g_return_val_if_fail(account != NULL, NULL);
2975 type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, NOVELL_STATUS_TYPE_AVAILABLE,
2976 NULL, TRUE, TRUE, FALSE,
2977 "message", _("Message"), purple_value_new(G_TYPE_STRING),
2978 NULL);
2979 status_types = g_list_append(status_types, type);
2981 type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, NOVELL_STATUS_TYPE_AWAY,
2982 NULL, TRUE, TRUE, FALSE,
2983 "message", _("Message"), purple_value_new(G_TYPE_STRING),
2984 NULL);
2985 status_types = g_list_append(status_types, type);
2987 type = purple_status_type_new_with_attrs(PURPLE_STATUS_UNAVAILABLE, NOVELL_STATUS_TYPE_BUSY,
2988 _("Busy"), TRUE, TRUE, FALSE,
2989 "message", _("Message"), purple_value_new(G_TYPE_STRING),
2990 NULL);
2991 status_types = g_list_append(status_types, type);
2993 type = purple_status_type_new_full(PURPLE_STATUS_INVISIBLE, NOVELL_STATUS_TYPE_APPEAR_OFFLINE,
2994 NULL, TRUE, TRUE, FALSE);
2995 status_types = g_list_append(status_types, type);
2997 type = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, NULL, NULL, TRUE, TRUE, FALSE);
2998 status_types = g_list_append(status_types, type);
3000 return status_types;
3003 static void
3004 novell_set_status(PurpleAccount *account, PurpleStatus *status)
3006 PurpleConnection *gc;
3007 gboolean connected;
3008 PurplePresence *presence;
3009 PurpleStatusType *type;
3010 PurpleStatusPrimitive primitive;
3011 NMUser *user;
3012 NMSTATUS_T novellstatus = NM_STATUS_AVAILABLE;
3013 NMERR_T rc = NM_OK;
3014 const char *msg = NULL;
3015 char *text = NULL;
3017 connected = purple_account_is_connected(account);
3018 presence = purple_status_get_presence(status);
3019 type = purple_status_get_status_type(status);
3020 primitive = purple_status_type_get_primitive(type);
3023 * We don't have any independent statuses, so we don't need to
3024 * do anything when a status is deactivated (because another
3025 * status is about to be activated).
3027 if (!purple_status_is_active(status))
3028 return;
3030 if (!connected)
3031 return;
3033 gc = purple_account_get_connection(account);
3034 user = purple_connection_get_protocol_data(gc);
3035 if (user == NULL)
3036 return;
3038 if (primitive == PURPLE_STATUS_AVAILABLE) {
3039 novellstatus = NM_STATUS_AVAILABLE;
3040 } else if (primitive == PURPLE_STATUS_AWAY) {
3041 novellstatus = NM_STATUS_AWAY;
3042 } else if (primitive == PURPLE_STATUS_UNAVAILABLE) {
3043 novellstatus = NM_STATUS_BUSY;
3044 } else if (primitive == PURPLE_STATUS_INVISIBLE) {
3045 novellstatus = NM_STATUS_OFFLINE;
3046 } else if (purple_presence_is_idle(presence)) {
3047 novellstatus = NM_STATUS_AWAY_IDLE;
3048 } else {
3049 novellstatus = NM_STATUS_AVAILABLE;
3052 if (primitive == PURPLE_STATUS_AWAY || primitive == PURPLE_STATUS_AVAILABLE ||
3053 primitive == PURPLE_STATUS_UNAVAILABLE) {
3054 msg = purple_status_get_attr_string(status, "message");
3055 text = g_strdup(msg);
3057 if (primitive == PURPLE_STATUS_AVAILABLE)
3058 msg = NULL; /* no auto replies for online status */
3060 /* Don't want newlines in status text */
3061 purple_util_chrreplace(text, '\n', ' ');
3064 rc = nm_send_set_status(user, novellstatus, text, msg, NULL, NULL);
3065 _check_for_disconnect(user, rc);
3067 g_free(text);
3070 static void
3071 novell_add_permit(PurpleConnection *gc, const char *who)
3073 NMUser *user;
3074 NMERR_T rc = NM_OK;
3075 const char *name = who;
3077 if (gc == NULL || who == NULL)
3078 return;
3080 user = purple_connection_get_protocol_data(gc);
3081 if (user == NULL)
3082 return;
3084 /* Remove first -- we will add it back in when we get
3085 * the okay from the server
3087 purple_account_privacy_permit_remove(purple_connection_get_account(gc), who, TRUE);
3089 if (nm_user_is_privacy_locked(user)) {
3090 _show_privacy_locked_error(gc, user);
3091 _sync_privacy_lists(user);
3092 return;
3095 /* Work around for problem with un-typed, dotted contexts */
3096 if (strchr(who, '.')) {
3097 const char *dn = nm_lookup_dn(user, who);
3098 if (dn == NULL) {
3099 rc = nm_send_get_details(user, who,
3100 _get_details_send_privacy_create,
3101 GINT_TO_POINTER(TRUE));
3102 _check_for_disconnect(user, rc);
3103 return;
3104 } else {
3105 name = dn;
3109 rc = nm_send_create_privacy_item(user, name, TRUE,
3110 _create_privacy_item_permit_resp_cb,
3111 g_strdup(who));
3112 _check_for_disconnect(user, rc);
3115 static void
3116 novell_add_deny(PurpleConnection *gc, const char *who)
3118 NMUser *user;
3119 NMERR_T rc = NM_OK;
3120 const char *name = who;
3122 if (gc == NULL || who == NULL)
3123 return;
3125 user = purple_connection_get_protocol_data(gc);
3126 if (user == NULL)
3127 return;
3129 /* Remove first -- we will add it back in when we get
3130 * the okay from the server
3132 purple_account_privacy_deny_remove(purple_connection_get_account(gc), who, TRUE);
3134 if (nm_user_is_privacy_locked(user)) {
3135 _show_privacy_locked_error(gc, user);
3136 _sync_privacy_lists(user);
3137 return;
3140 /* Work around for problem with un-typed, dotted contexts */
3141 if (strchr(who, '.')) {
3142 const char *dn = nm_lookup_dn(user, who);
3143 if (dn == NULL) {
3144 rc = nm_send_get_details(user, who,
3145 _get_details_send_privacy_create,
3146 GINT_TO_POINTER(FALSE));
3147 _check_for_disconnect(user, rc);
3148 return;
3149 } else {
3150 name = dn;
3154 rc = nm_send_create_privacy_item(user, name, FALSE,
3155 _create_privacy_item_deny_resp_cb,
3156 g_strdup(who));
3157 _check_for_disconnect(user, rc);
3160 static void
3161 novell_rem_permit(PurpleConnection *gc, const char *who)
3163 NMUser *user;
3164 NMERR_T rc = NM_OK;
3165 const char *dn = NULL;
3167 if (gc == NULL || who == NULL)
3168 return;
3170 user = purple_connection_get_protocol_data(gc);
3171 if (user == NULL)
3172 return;
3174 if (nm_user_is_privacy_locked(user)) {
3175 _show_privacy_locked_error(gc, user);
3176 _sync_privacy_lists(user);
3177 return;
3180 dn = nm_lookup_dn(user, who);
3181 if (dn == NULL)
3182 dn = who;
3184 rc = nm_send_remove_privacy_item(user, dn, TRUE,
3185 _remove_privacy_item_resp_cb,
3186 g_strdup(who));
3187 _check_for_disconnect(user, rc);
3190 static void
3191 novell_rem_deny(PurpleConnection *gc, const char *who)
3193 NMUser *user;
3194 NMERR_T rc = NM_OK;
3195 const char *dn = NULL;
3197 if (gc == NULL || who == NULL)
3198 return;
3200 user = purple_connection_get_protocol_data(gc);
3201 if (user == NULL)
3202 return;
3204 if (nm_user_is_privacy_locked(user)) {
3205 _show_privacy_locked_error(gc, user);
3206 _sync_privacy_lists(user);
3207 return;
3210 dn = nm_lookup_dn(user, who);
3211 if (dn == NULL)
3212 dn = who;
3214 rc = nm_send_remove_privacy_item(user, dn, FALSE,
3215 _remove_privacy_item_resp_cb,
3216 g_strdup(who));
3217 _check_for_disconnect(user, rc);
3220 static void
3221 novell_set_permit_deny(PurpleConnection *gc)
3223 NMERR_T rc = NM_OK;
3224 const char *dn, *name = NULL;
3225 NMUserRecord *user_record = NULL;
3226 GSList *node = NULL, *copy = NULL;
3227 NMUser *user;
3228 int i, j, num_contacts, num_folders;
3229 NMContact *contact;
3230 NMFolder *folder = NULL;
3231 PurpleAccount *account;
3233 if (gc == NULL)
3234 return;
3236 account = purple_connection_get_account(gc);
3238 user = purple_connection_get_protocol_data(gc);
3239 if (user == NULL)
3240 return;
3242 if (user->privacy_synched == FALSE) {
3243 _sync_privacy_lists(user);
3244 user->privacy_synched = TRUE;
3245 return;
3248 if (nm_user_is_privacy_locked(user)) {
3249 _show_privacy_locked_error(gc, user);
3250 _sync_privacy_lists(user);
3251 return;
3254 switch (purple_account_get_privacy_type(account)) {
3256 case PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL:
3257 rc = nm_send_set_privacy_default(user, FALSE,
3258 _set_privacy_default_resp_cb, NULL);
3259 _check_for_disconnect(user, rc);
3261 /* clear server side deny list */
3262 if (rc == NM_OK) {
3263 copy = g_slist_copy(user->deny_list);
3264 for (node = copy; node && node->data; node = node->next) {
3265 rc = nm_send_remove_privacy_item(user, (const char *)node->data,
3266 FALSE, NULL, NULL);
3267 if (_check_for_disconnect(user, rc))
3268 break;
3270 g_slist_free(copy);
3271 g_slist_free(user->deny_list);
3272 user->deny_list = NULL;
3274 break;
3276 case PURPLE_ACCOUNT_PRIVACY_DENY_ALL:
3277 rc = nm_send_set_privacy_default(user, TRUE,
3278 _set_privacy_default_resp_cb, NULL);
3279 _check_for_disconnect(user, rc);
3281 /* clear server side allow list */
3282 if (rc == NM_OK) {
3283 copy = g_slist_copy(user->allow_list);
3284 for (node = copy; node && node->data; node = node->next) {
3285 rc = nm_send_remove_privacy_item(user, (const char *)node->data,
3286 TRUE, NULL, NULL);
3287 if (_check_for_disconnect(user, rc))
3288 break;
3290 g_slist_free(copy);
3291 g_slist_free(user->allow_list);
3292 user->allow_list = NULL;
3294 break;
3296 case PURPLE_ACCOUNT_PRIVACY_ALLOW_USERS:
3298 rc = nm_send_set_privacy_default(user, TRUE,
3299 _set_privacy_default_resp_cb, NULL);
3300 _check_for_disconnect(user, rc);
3302 /* sync allow lists */
3303 if (rc == NM_OK) {
3305 for (node = user->allow_list; node; node = node->next) {
3306 user_record = nm_find_user_record(user, (char *)node->data);
3307 if (user_record) {
3308 name = nm_user_record_get_display_id(user_record);
3310 if (!g_slist_find_custom(purple_account_privacy_get_permitted(account),
3311 name, (GCompareFunc)purple_utf8_strcasecmp)) {
3312 purple_account_privacy_permit_add(account, name , TRUE);
3317 for (node = purple_account_privacy_get_permitted(account); node; node = node->next) {
3318 dn = nm_lookup_dn(user, (char *)node->data);
3319 if (dn) {
3321 if (!g_slist_find_custom(user->allow_list,
3322 dn, (GCompareFunc)purple_utf8_strcasecmp)) {
3323 rc = nm_send_create_privacy_item(user, dn, TRUE,
3324 _create_privacy_item_deny_resp_cb,
3325 g_strdup(dn));
3326 _check_for_disconnect(user, rc);
3328 } else {
3329 purple_account_privacy_permit_remove(account, (char *)node->data, TRUE);
3333 break;
3335 case PURPLE_ACCOUNT_PRIVACY_DENY_USERS:
3337 /* set to default allow */
3338 rc = nm_send_set_privacy_default(user, FALSE,
3339 _set_privacy_default_resp_cb, NULL);
3340 _check_for_disconnect(user, rc);
3342 /* sync deny lists */
3343 if (rc == NM_OK) {
3345 for (node = user->deny_list; node; node = node->next) {
3346 user_record = nm_find_user_record(user, (char *)node->data);
3347 if (user_record) {
3348 name = nm_user_record_get_display_id(user_record);
3350 if (!g_slist_find_custom(purple_account_privacy_get_denied(account),
3351 name, (GCompareFunc)purple_utf8_strcasecmp)) {
3352 purple_account_privacy_deny_add(account, name , TRUE);
3357 for (node = purple_account_privacy_get_denied(account); node; node = node->next) {
3359 name = NULL;
3360 dn = nm_lookup_dn(user, (char *)node->data);
3361 if (dn) {
3362 user_record = nm_find_user_record(user, dn);
3363 name = nm_user_record_get_display_id(user_record);
3365 if (!g_slist_find_custom(user->deny_list,
3366 dn, (GCompareFunc)purple_utf8_strcasecmp)) {
3367 rc = nm_send_create_privacy_item(user, dn, FALSE,
3368 _create_privacy_item_deny_resp_cb,
3369 g_strdup(name));
3370 _check_for_disconnect(user, rc);
3372 } else {
3373 purple_account_privacy_deny_remove(account, (char *)node->data, TRUE);
3378 break;
3380 case PURPLE_ACCOUNT_PRIVACY_ALLOW_BUDDYLIST:
3382 /* remove users from allow list that are not in buddy list */
3383 copy = g_slist_copy(user->allow_list);
3384 for (node = copy; node && node->data; node = node->next) {
3385 if (!nm_find_contacts(user, node->data)) {
3386 rc = nm_send_remove_privacy_item(user, (const char *)node->data,
3387 TRUE, NULL, NULL);
3388 if (_check_for_disconnect(user, rc))
3389 return;
3392 g_slist_free(copy);
3394 /* add all buddies to allow list */
3395 num_contacts = nm_folder_get_contact_count(user->root_folder);
3396 for (i = 0; i < num_contacts; i++) {
3397 contact = nm_folder_get_contact(user->root_folder, i);
3398 dn = nm_contact_get_dn(contact);
3399 if (dn && !g_slist_find_custom(user->allow_list,
3400 dn, (GCompareFunc)purple_utf8_strcasecmp))
3402 rc = nm_send_create_privacy_item(user, dn, TRUE,
3403 _create_privacy_item_deny_resp_cb,
3404 g_strdup(dn));
3405 if (_check_for_disconnect(user, rc))
3406 return;
3411 num_folders = nm_folder_get_subfolder_count(user->root_folder);
3412 for (i = 0; i < num_folders; i++) {
3413 folder = nm_folder_get_subfolder(user->root_folder, i);
3414 num_contacts = nm_folder_get_contact_count(folder);
3415 for (j = 0; j < num_contacts; j++) {
3416 contact = nm_folder_get_contact(folder, j);
3417 dn = nm_contact_get_dn(contact);
3418 if (dn && !g_slist_find_custom(user->allow_list,
3419 dn, (GCompareFunc)purple_utf8_strcasecmp))
3421 rc = nm_send_create_privacy_item(user, dn, TRUE,
3422 _create_privacy_item_deny_resp_cb,
3423 g_strdup(dn));
3424 if (_check_for_disconnect(user, rc))
3425 return;
3430 /* set to default deny */
3431 rc = nm_send_set_privacy_default(user, TRUE,
3432 _set_privacy_default_resp_cb, NULL);
3433 if (_check_for_disconnect(user, rc))
3434 break;
3436 break;
3440 static GList *
3441 novell_blist_node_menu(PurpleBlistNode *node)
3443 GList *list = NULL;
3444 PurpleActionMenu *act;
3446 if(PURPLE_IS_BUDDY(node)) {
3447 act = purple_action_menu_new(_("Initiate _Chat"),
3448 PURPLE_CALLBACK(_initiate_conference_cb),
3449 NULL, NULL);
3450 list = g_list_append(list, act);
3453 return list;
3456 static void
3457 novell_keepalive(PurpleConnection *gc)
3459 NMUser *user;
3460 NMERR_T rc = NM_OK;
3462 if (gc == NULL)
3463 return;
3465 user = purple_connection_get_protocol_data(gc);
3466 if (user == NULL)
3467 return;
3469 rc = nm_send_keepalive(user, NULL, NULL);
3470 _check_for_disconnect(user, rc);
3473 static gssize
3474 novell_get_max_message_size(PurpleConversation *conv)
3476 /* XXX: got from pidgin-otr - verify and document it */
3477 return 1792;
3480 static void
3481 novell_protocol_init(NovellProtocol *self)
3483 PurpleProtocol *protocol = PURPLE_PROTOCOL(self);
3484 PurpleAccountOption *option;
3486 protocol->id = "prpl-novell";
3487 protocol->name = "GroupWise";
3489 option = purple_account_option_string_new(_("Server address"), "server", NULL);
3490 protocol->account_options =
3491 g_list_append(protocol->account_options, option);
3493 option = purple_account_option_int_new(_("Server port"), "port", DEFAULT_PORT);
3494 protocol->account_options =
3495 g_list_append(protocol->account_options, option);
3498 static void
3499 novell_protocol_class_init(NovellProtocolClass *klass)
3501 PurpleProtocolClass *protocol_class = PURPLE_PROTOCOL_CLASS(klass);
3503 protocol_class->login = novell_login;
3504 protocol_class->close = novell_close;
3505 protocol_class->status_types = novell_status_types;
3506 protocol_class->list_icon = novell_list_icon;
3509 static void
3510 novell_protocol_class_finalize(G_GNUC_UNUSED NovellProtocolClass *klass)
3514 static void
3515 novell_protocol_client_iface_init(PurpleProtocolClientInterface *client_iface)
3517 client_iface->status_text = novell_status_text;
3518 client_iface->tooltip_text = novell_tooltip_text;
3519 client_iface->blist_node_menu = novell_blist_node_menu;
3520 client_iface->convo_closed = novell_convo_closed;
3521 client_iface->normalize = purple_normalize_nocase;
3522 client_iface->get_max_message_size = novell_get_max_message_size;
3525 static void
3526 novell_protocol_server_iface_init(PurpleProtocolServerInterface *server_iface)
3528 server_iface->get_info = novell_get_info;
3529 server_iface->set_status = novell_set_status;
3530 server_iface->set_idle = novell_set_idle;
3531 server_iface->add_buddy = novell_add_buddy;
3532 server_iface->remove_buddy = novell_remove_buddy;
3533 server_iface->keepalive = novell_keepalive;
3534 server_iface->alias_buddy = novell_alias_buddy;
3535 server_iface->group_buddy = novell_group_buddy;
3536 server_iface->rename_group = novell_rename_group;
3537 server_iface->remove_group = novell_remove_group;
3540 static void
3541 novell_protocol_im_iface_init(PurpleProtocolIMInterface *im_iface)
3543 im_iface->send = novell_send_im;
3544 im_iface->send_typing = novell_send_typing;
3547 static void
3548 novell_protocol_chat_iface_init(PurpleProtocolChatInterface *chat_iface)
3550 chat_iface->invite = novell_chat_invite;
3551 chat_iface->leave = novell_chat_leave;
3552 chat_iface->send = novell_chat_send;
3555 static void
3556 novell_protocol_privacy_iface_init(PurpleProtocolPrivacyInterface *privacy_iface)
3558 privacy_iface->add_permit = novell_add_permit;
3559 privacy_iface->add_deny = novell_add_deny;
3560 privacy_iface->rem_permit = novell_rem_permit;
3561 privacy_iface->rem_deny = novell_rem_deny;
3562 privacy_iface->set_permit_deny = novell_set_permit_deny;
3565 G_DEFINE_DYNAMIC_TYPE_EXTENDED(
3566 NovellProtocol, novell_protocol, PURPLE_TYPE_PROTOCOL, 0,
3568 G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CLIENT,
3569 novell_protocol_client_iface_init)
3571 G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_SERVER,
3572 novell_protocol_server_iface_init)
3574 G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_IM,
3575 novell_protocol_im_iface_init)
3577 G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CHAT,
3578 novell_protocol_chat_iface_init)
3580 G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_PRIVACY,
3581 novell_protocol_privacy_iface_init));
3583 static PurplePluginInfo *
3584 plugin_query(GError **error)
3586 return purple_plugin_info_new(
3587 "id", "prpl-novell",
3588 "name", "Novell GroupWise Protocol",
3589 "version", DISPLAY_VERSION,
3590 "category", N_("Protocol"),
3591 "summary", N_("Novell GroupWise Messenger Protocol Plugin"),
3592 "description", N_("Novell GroupWise Messenger Protocol Plugin"),
3593 "website", PURPLE_WEBSITE,
3594 "abi-version", PURPLE_ABI_VERSION,
3595 "flags", PURPLE_PLUGIN_INFO_FLAGS_INTERNAL |
3596 PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD,
3597 NULL
3601 static gboolean
3602 plugin_load(PurplePlugin *plugin, GError **error)
3604 novell_protocol_register_type(G_TYPE_MODULE(plugin));
3606 my_protocol = purple_protocols_add(NOVELL_TYPE_PROTOCOL, error);
3607 if (!my_protocol)
3608 return FALSE;
3610 return TRUE;
3613 static gboolean
3614 plugin_unload(PurplePlugin *plugin, GError **error)
3616 if (!purple_protocols_remove(my_protocol, error))
3617 return FALSE;
3619 return TRUE;
3622 PURPLE_PLUGIN_INIT(novell, plugin_query, plugin_load, plugin_unload);