Mercurial > pidgin.yaz
view libpurple/protocols/novell/novell.c @ 20570:5913725cbcd6
Use an independant status type for 'current media' stuff, instead of using
status attributes. This includes changes in both xmpp and msn.
Also, in MSN, CurrentMedia is sent with PSM if you turn on the status and
set the attributes on the account.
author | Sadrul Habib Chowdhury <imadil@gmail.com> |
---|---|
date | Thu, 20 Sep 2007 16:30:17 +0000 |
parents | 44b4e8bd759b |
children | 6a0d9fa477d4 b2c46103a5b4 5723dbc6212d |
line wrap: on
line source
/* * novell.c * * Copyright (c) 2004 Novell, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA * */ #include "internal.h" #include "accountopt.h" #include "debug.h" #include "prpl.h" #include "server.h" #include "nmuser.h" #include "notify.h" #include "util.h" #include "sslconn.h" #include "request.h" #include "network.h" #include "privacy.h" #include "status.h" #include "version.h" #define DEFAULT_PORT 8300 #define NOVELL_CONNECT_STEPS 4 #define NM_ROOT_FOLDER_NAME "GroupWise Messenger" #define NOVELL_STATUS_TYPE_AVAILABLE "available" #define NOVELL_STATUS_TYPE_AWAY "away" #define NOVELL_STATUS_TYPE_BUSY "busy" #define NOVELL_STATUS_TYPE_OFFLINE "offline" #define NOVELL_STATUS_TYPE_IDLE "idle" #define NOVELL_STATUS_TYPE_APPEAR_OFFLINE "appearoffline" static PurplePlugin *my_protocol = NULL; static gboolean _is_disconnect_error(NMERR_T err); static gboolean _check_for_disconnect(NMUser * user, NMERR_T err); static void _send_message(NMUser * user, NMMessage * message); static void _update_buddy_status(NMUser *user, PurpleBuddy * buddy, int status, int gmt); static void _remove_purple_buddies(NMUser * user); static void _add_contacts_to_purple_blist(NMUser * user, NMFolder * folder); static void _add_purple_buddies(NMUser * user); static void _sync_contact_list(NMUser *user); static void _sync_privacy_lists(NMUser *user); static void _show_info(PurpleConnection * gc, NMUserRecord * user_record); const char * _get_conference_name(int id); /******************************************************************************* * Response callbacks *******************************************************************************/ /* Handle login response */ static void _login_resp_cb(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { PurpleConnection *gc; const char *alias; NMERR_T rc; if (user == NULL) return; gc = purple_account_get_connection(user->client_data); if (gc == NULL) return; if (ret_code == NM_OK) { /* Set alias for user if not set (use Full Name) */ alias = purple_account_get_alias(user->client_data); if (alias == NULL || *alias == '\0') { alias = nm_user_record_get_full_name(user->user_record); if (alias) purple_account_set_alias(user->client_data, alias); } /* Tell Purple that we are connected */ purple_connection_set_state(gc, PURPLE_CONNECTED); _sync_contact_list(user); rc = nm_send_set_status(user, NM_STATUS_AVAILABLE, NULL, NULL, NULL, NULL); _check_for_disconnect(user, rc); } else { char *err = g_strdup_printf(_("Login failed (%s)."), nm_error_to_string (ret_code)); /* Don't attempt to auto-reconnect if our password * was invalid. */ if (ret_code == NMERR_AUTHENTICATION_FAILED || ret_code == NMERR_CREDENTIALS_MISSING || ret_code == NMERR_PASSWORD_INVALID) { gc->wants_to_die = TRUE; } purple_connection_error(gc, err); g_free(err); } } /* Handle getstatus response*/ static void _get_status_resp_cb(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { PurpleBuddy *buddy; GSList *buddies; GSList *bnode; NMUserRecord *user_record = (NMUserRecord *) resp_data; int status; if (user == NULL || user_record == NULL) return; if (ret_code == NM_OK) { /* Find all Purple buddies and update their statuses */ const char *name = nm_user_record_get_display_id(user_record); if (name) { buddies = purple_find_buddies((PurpleAccount *) user->client_data, name); for (bnode = buddies; bnode; bnode = bnode->next) { buddy = (PurpleBuddy *) bnode->data; if (buddy) { status = nm_user_record_get_status(user_record); _update_buddy_status(user, buddy, status, time(0)); } } g_slist_free(buddies); } } else { purple_debug(PURPLE_DEBUG_INFO, "novell", "_get_status_resp_cb(): rc = 0x%X\n", ret_code); } } /* Show an error if the rename failed */ static void _rename_contact_resp_cb(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { if (ret_code != NM_OK) { purple_debug(PURPLE_DEBUG_INFO, "novell", "_rename_contact_resp_cb(): rc = 0x%X\n", ret_code); } } /* Handle the getdetails response and send the message */ static void _get_details_resp_send_msg(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { PurpleConversation *gconv; PurpleConnection *gc; NMUserRecord *user_record = NULL; NMContact *cntct = NULL; NMConference *conf; NMMessage *msg = user_data; const char *dn = NULL; const char *name; if (user == NULL || msg == NULL) return; if (ret_code == NM_OK) { user_record = (NMUserRecord *) resp_data; if (user_record) { /* Set the title for the conversation */ /* XXX - Should this be PURPLE_CONV_TYPE_IM? */ gconv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, nm_user_record_get_display_id(user_record), (PurpleAccount *) user->client_data); if (gconv) { dn = nm_user_record_get_dn(user_record); if (dn) { cntct = nm_find_contact(user, dn); } if (cntct) { purple_conversation_set_title(gconv, nm_contact_get_display_name(cntct)); } else { /* Not in the contact list, try to user full name */ name = (char *) nm_user_record_get_full_name(user_record); if (name) purple_conversation_set_title(gconv, name); } } /* Add the user record to particpant list */ conf = nm_message_get_conference(msg); if (conf) { nm_conference_add_participant(conf, user_record); _send_message(user, msg); } } } else { gc = purple_account_get_connection(user->client_data); if (gc != NULL) { char *err = g_strdup_printf(_("Unable to send message." " Could not get details for user (%s)."), nm_error_to_string (ret_code)); purple_notify_error(gc, NULL, err, NULL); g_free(err); } if (msg) nm_release_message(msg); } } /* Set up the new PurpleBuddy based on the response from getdetails */ static void _get_details_resp_setup_buddy(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { NMUserRecord *user_record; NMContact *contact; PurpleBuddy *buddy; const char *alias; NMERR_T rc = NM_OK; if (user == NULL || resp_data == NULL || user_data == NULL) return; contact = user_data; if (ret_code == NM_OK) { user_record = resp_data; buddy = nm_contact_get_data(contact); nm_contact_set_user_record(contact, user_record); /* Set the display id */ purple_blist_rename_buddy(buddy, nm_user_record_get_display_id(user_record)); alias = purple_buddy_get_alias(buddy); if (alias == NULL || *alias == '\0' || (strcmp(alias, buddy->name) == 0)) { purple_blist_alias_buddy(buddy, nm_user_record_get_full_name(user_record)); /* Tell the server about the new display name */ rc = nm_send_rename_contact(user, contact, nm_user_record_get_full_name(user_record), NULL, NULL); _check_for_disconnect(user, rc); } /* Get initial status for the buddy */ rc = nm_send_get_status(user, resp_data, _get_status_resp_cb, NULL); _check_for_disconnect(user, rc); /* nm_release_contact(contact);*/ } if (contact) nm_release_contact(contact); } /* Add the new contact into the PurpleBuddy list */ static void _create_contact_resp_cb(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { NMContact *tmp_contact = (NMContact *) user_data; NMContact *new_contact = NULL; NMFolder *folder = NULL; PurpleGroup *group; PurpleBuddy *buddy; const char *folder_name = NULL; NMERR_T rc = NM_OK; if (user == NULL) return; if (ret_code == NM_OK) { new_contact = (NMContact *) resp_data; if (new_contact == NULL || tmp_contact == NULL) return; /* Get the userid and folder name for the new contact */ folder = nm_find_folder_by_id(user, nm_contact_get_parent_id(new_contact)); if (folder) { folder_name = nm_folder_get_name(folder); } if (folder_name == NULL || *folder_name == '\0') folder_name = NM_ROOT_FOLDER_NAME; /* Re-add the buddy now that we got the okay from the server */ if (folder_name && (group = purple_find_group(folder_name))) { const char *alias = nm_contact_get_display_name(tmp_contact); const char *display_id = nm_contact_get_display_id(new_contact); if (display_id == NULL) display_id = nm_contact_get_dn(new_contact); if (alias && strcmp(alias, display_id)) { /* The user requested an alias, tell the server about it. */ rc = nm_send_rename_contact(user, new_contact, alias, _rename_contact_resp_cb, NULL); _check_for_disconnect(user, rc); } else { alias = ""; } /* Add it to the purple buddy list if it is not there */ buddy = purple_find_buddy_in_group(user->client_data, display_id, group); if (buddy == NULL) { buddy = purple_buddy_new(user->client_data, display_id, alias); purple_blist_add_buddy(buddy, NULL, group, NULL); } /* Save the new buddy as part of the contact object */ nm_contact_set_data(new_contact, (gpointer) buddy); /* We need details for the user before we can setup the * new Purple buddy. We always call this because the * 'createcontact' response fields do not always contain * everything that we need. */ nm_contact_add_ref(new_contact); rc = nm_send_get_details(user, nm_contact_get_dn(new_contact), _get_details_resp_setup_buddy, new_contact); _check_for_disconnect(user, rc); } } else { PurpleConnection *gc = purple_account_get_connection(user->client_data); const char *name = nm_contact_get_dn(tmp_contact); char *err; err = g_strdup_printf(_("Unable to add %s to your buddy list (%s)."), name, nm_error_to_string (ret_code)); purple_notify_error(gc, NULL, err, NULL); g_free(err); } if (tmp_contact) nm_release_contact(tmp_contact); } /* Show an error if we failed to send the message */ static void _send_message_resp_cb(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { PurpleConnection *gc; char *err = NULL; if (user == NULL) return; if (ret_code != NM_OK) { gc = purple_account_get_connection(user->client_data); /* TODO: Improve this! message to who or for what conference? */ err = g_strdup_printf(_("Unable to send message (%s)."), nm_error_to_string (ret_code)); purple_notify_error(gc, NULL, err, NULL); g_free(err); } } /* Show an error if the remove failed */ static void _remove_contact_resp_cb(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { if (ret_code != NM_OK) { /* TODO: Display an error? */ purple_debug(PURPLE_DEBUG_INFO, "novell", "_remove_contact_resp_cb(): rc = 0x%x\n", ret_code); } } /* Show an error if the remove failed */ static void _remove_folder_resp_cb(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { if (ret_code != NM_OK) { /* TODO: Display an error? */ purple_debug(PURPLE_DEBUG_INFO, "novell", "_remove_folder_resp_cb(): rc = 0x%x\n", ret_code); } } /* Show an error if the move failed */ static void _move_contact_resp_cb(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { if (ret_code != NM_OK) { /* TODO: Display an error? */ purple_debug(PURPLE_DEBUG_INFO, "novell", "_move_contact_resp_cb(): rc = 0x%x\n", ret_code); } } /* Show an error if the rename failed */ static void _rename_folder_resp_cb(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { if (ret_code != NM_OK) { /* TODO: Display an error? */ purple_debug(PURPLE_DEBUG_INFO, "novell", "_rename_folder_resp_cb(): rc = 0x%x\n", ret_code); } } static void _sendinvite_resp_cb(NMUser *user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { char *err; PurpleConnection *gc; if (user == NULL) return; if (ret_code != NM_OK) { gc = purple_account_get_connection(user->client_data); err = g_strdup_printf(_("Unable to invite user (%s)."), nm_error_to_string(ret_code)); purple_notify_error(gc, NULL, err, NULL); g_free(err); purple_debug(PURPLE_DEBUG_INFO, "novell", "_sendinvite_resp_cb(): rc = 0x%x\n", ret_code); } } /* If the createconf was successful attempt to send the message, * otherwise display an error message to the user. */ static void _createconf_resp_send_msg(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { NMConference *conf; NMMessage *msg = user_data; if (user == NULL || msg == NULL) return; if (ret_code == NM_OK) { _send_message(user, msg); } else { if ((conf = nm_message_get_conference(msg))) { PurpleConnection *gc = purple_account_get_connection(user->client_data); const char *name = NULL; char *err; NMUserRecord *ur; ur = nm_conference_get_participant(conf, 0); if (ur) name = nm_user_record_get_userid(ur); if (name) err = g_strdup_printf(_("Unable to send message to %s." " Could not create the conference (%s)."), name, nm_error_to_string (ret_code)); else err = g_strdup_printf(_("Unable to send message." " Could not create the conference (%s)."), nm_error_to_string (ret_code)); purple_notify_error(gc, NULL, err, NULL); g_free(err); } if (msg) nm_release_message(msg); } } /* Move contact to newly created folder */ static void _create_folder_resp_move_contact(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { NMContact *contact = user_data; NMFolder *new_folder; char *folder_name = resp_data; NMERR_T rc = NM_OK; if (user == NULL || folder_name == NULL || contact == NULL) { if (folder_name) g_free(folder_name); return; } if (ret_code == NM_OK || ret_code == NMERR_DUPLICATE_FOLDER) { new_folder = nm_find_folder(user, folder_name); if (new_folder) { /* Tell the server to move the contact to the new folder */ /* rc = nm_send_move_contact(user, contact, new_folder, _move_contact_resp_cb, NULL); */ rc = nm_send_create_contact(user, new_folder, contact, NULL, NULL); _check_for_disconnect(user, rc); } } else { PurpleConnection *gc = purple_account_get_connection(user->client_data); char *err = g_strdup_printf(_("Unable to move user %s" " to folder %s in the server side list." " Error while creating folder (%s)."), nm_contact_get_dn(contact), folder_name, nm_error_to_string (ret_code)); purple_notify_error(gc, NULL, err, NULL); g_free(err); } if (folder_name) g_free(folder_name); } /* Add contact to newly create folder */ static void _create_folder_resp_add_contact(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { NMContact *contact = (NMContact *) user_data; NMFolder *folder; char *folder_name = (char *) resp_data; NMERR_T rc = NM_OK; if (user == NULL || folder_name == NULL || contact == NULL) { if (contact) nm_release_contact(contact); if (folder_name) g_free(folder_name); return; } if (ret_code == NM_OK || ret_code == NMERR_DUPLICATE_FOLDER) { folder = nm_find_folder(user, folder_name); if (folder) { rc = nm_send_create_contact(user, folder, contact, _create_contact_resp_cb, contact); _check_for_disconnect(user, rc); } } else { PurpleConnection *gc = purple_account_get_connection(user->client_data); const char *name = nm_contact_get_dn(contact); char *err = g_strdup_printf(_("Unable to add %s to your buddy list." " Error creating folder in server side list (%s)."), name, nm_error_to_string (ret_code)); purple_notify_error(gc, NULL, err, NULL); nm_release_contact(contact); g_free(err); } g_free(folder_name); } static void _join_conf_resp_cb(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { PurpleConversation *chat; PurpleConnection *gc; NMUserRecord *ur; NMConference *conference = user_data; const char *name, *conf_name; int i, count; if (user == NULL || conference == NULL) return; gc = purple_account_get_connection(user->client_data); if (ret_code == NM_OK) { conf_name = _get_conference_name(++user->conference_count); chat = serv_got_joined_chat(gc, user->conference_count, conf_name); if (chat) { nm_conference_set_data(conference, (gpointer) chat); count = nm_conference_get_participant_count(conference); for (i = 0; i < count; i++) { ur = nm_conference_get_participant(conference, i); if (ur) { name = nm_user_record_get_display_id(ur); purple_conv_chat_add_user(PURPLE_CONV_CHAT(chat), name, NULL, PURPLE_CBFLAGS_NONE, TRUE); } } } } } /* Show info returned by getdetails */ static void _get_details_resp_show_info(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { PurpleConnection *gc; NMUserRecord *user_record; char *name; char *err; if (user == NULL) return; name = user_data; if (ret_code == NM_OK) { user_record = (NMUserRecord *) resp_data; if (user_record) { _show_info(purple_account_get_connection(user->client_data), user_record); } } else { gc = purple_account_get_connection(user->client_data); err = g_strdup_printf(_("Could not get details for user %s (%s)."), name, nm_error_to_string (ret_code)); purple_notify_error(gc, NULL, err, NULL); g_free(err); } if (name) g_free(name); } /* Handle get details response add to privacy list */ static void _get_details_resp_add_privacy_item(NMUser *user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { PurpleConnection *gc; NMUserRecord *user_record = resp_data; char *err; gboolean allowed = GPOINTER_TO_INT(user_data); const char *display_id; if (user == NULL) return; gc = purple_account_get_connection(user->client_data); display_id = nm_user_record_get_display_id(user_record); if (ret_code == NM_OK) { if (allowed) { if (!g_slist_find_custom(gc->account->permit, display_id, (GCompareFunc)purple_utf8_strcasecmp)) { purple_privacy_permit_add(gc->account, display_id, TRUE); } } else { if (!g_slist_find_custom(gc->account->permit, display_id, (GCompareFunc)purple_utf8_strcasecmp)) { purple_privacy_deny_add(gc->account, display_id, TRUE); } } } else { err = g_strdup_printf(_("Unable to add user to privacy list (%s)."), nm_error_to_string(ret_code)); purple_notify_error(gc, NULL, err, NULL); g_free(err); } } /* Handle response to create privacy item request */ static void _create_privacy_item_deny_resp_cb(NMUser *user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { PurpleConnection *gc; NMUserRecord *user_record; char *who = user_data; char *err; NMERR_T rc = NM_OK; const char *display_id = NULL; if (user == NULL) return; gc = purple_account_get_connection(user->client_data); if (ret_code == NM_OK) { user_record = nm_find_user_record(user, who); if (user_record) display_id = nm_user_record_get_display_id(user_record); if (display_id) { if (!g_slist_find_custom(gc->account->deny, display_id, (GCompareFunc)purple_utf8_strcasecmp)) { purple_privacy_deny_add(gc->account, display_id, TRUE); } } else { rc = nm_send_get_details(user, who, _get_details_resp_add_privacy_item, (gpointer)FALSE); _check_for_disconnect(user, rc); } } else { err = g_strdup_printf(_("Unable to add %s to deny list (%s)."), who, nm_error_to_string(ret_code)); purple_notify_error(gc, NULL, err, NULL); g_free(err); } if (who) g_free(who); } /* Handle response to create privacy item request */ static void _create_privacy_item_permit_resp_cb(NMUser *user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { PurpleConnection *gc; NMUserRecord *user_record; char *who = user_data; char *err; NMERR_T rc = NM_OK; const char *display_id = NULL; if (user == NULL) return; gc = purple_account_get_connection(user->client_data); if (ret_code == NM_OK) { user_record = nm_find_user_record(user, who); if (user_record) display_id = nm_user_record_get_display_id(user_record); if (display_id) { if (!g_slist_find_custom(gc->account->permit, display_id, (GCompareFunc)purple_utf8_strcasecmp)) { purple_privacy_permit_add(gc->account, display_id, TRUE); } } else { rc = nm_send_get_details(user, who, _get_details_resp_add_privacy_item, (gpointer)TRUE); _check_for_disconnect(user, rc); } } else { err = g_strdup_printf(_("Unable to add %s to permit list (%s)."), who, nm_error_to_string(ret_code)); purple_notify_error(gc, NULL, err, NULL); g_free(err); } if (who) g_free(who); } static void _get_details_send_privacy_create(NMUser *user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { NMERR_T rc = NM_OK; PurpleConnection *gc; NMUserRecord *user_record = resp_data; char *err; gboolean allowed = GPOINTER_TO_INT(user_data); const char *dn, *display_id; if (user == NULL) return; gc = purple_account_get_connection(user->client_data); dn = nm_user_record_get_dn(user_record); display_id = nm_user_record_get_display_id(user_record); if (ret_code == NM_OK) { if (allowed) { rc = nm_send_create_privacy_item(user, dn, TRUE, _create_privacy_item_permit_resp_cb, g_strdup(display_id)); _check_for_disconnect(user, rc); } else { rc = nm_send_create_privacy_item(user, dn, FALSE, _create_privacy_item_deny_resp_cb, g_strdup(display_id)); _check_for_disconnect(user, rc); } } else { err = g_strdup_printf(_("Unable to add user to privacy list (%s)."), nm_error_to_string(ret_code)); purple_notify_error(gc, NULL, err, NULL); g_free(err); } } static void _remove_privacy_item_resp_cb(NMUser *user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { PurpleConnection *gc; char *who = user_data; char *err; if (user == NULL) return; if (ret_code != NM_OK) { gc = purple_account_get_connection(user->client_data); err = g_strdup_printf(_("Unable to remove %s from privacy list (%s)."), who, nm_error_to_string(ret_code)); purple_notify_error(gc, NULL, err, NULL); g_free(err); } if (who) g_free(who); } static void _set_privacy_default_resp_cb(NMUser *user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { PurpleConnection *gc; char *err; if (user == NULL) return; if (ret_code != NM_OK) { gc = purple_account_get_connection(user->client_data); err = g_strdup_printf(_("Unable to change server side privacy settings (%s)."), nm_error_to_string(ret_code)); purple_notify_error(gc, NULL, err, NULL); g_free(err); } } /* Handle get details response add to privacy list */ static void _get_details_resp_send_invite(NMUser *user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { NMERR_T rc = NM_OK; PurpleConnection *gc; NMUserRecord *user_record = resp_data; char *err; GSList *cnode; NMConference *conference; gpointer chat; long id = (long) user_data; if (user == NULL) return; gc = purple_account_get_connection(user->client_data); if (ret_code == NM_OK) { for (cnode = user->conferences; cnode != NULL; cnode = cnode->next) { conference = cnode->data; if (conference && (chat = nm_conference_get_data(conference))) { if (purple_conv_chat_get_id(PURPLE_CONV_CHAT(chat)) == id) { rc = nm_send_conference_invite(user, conference, user_record, NULL, _sendinvite_resp_cb, NULL); _check_for_disconnect(user, rc); break; } } } } else { err = g_strdup_printf(_("Unable to invite user (%s)."), nm_error_to_string(ret_code)); purple_notify_error(gc, NULL, err, NULL); g_free(err); } } static void _createconf_resp_send_invite(NMUser * user, NMERR_T ret_code, gpointer resp_data, gpointer user_data) { NMERR_T rc = NM_OK; NMConference *conference = resp_data; NMUserRecord *user_record = user_data; PurpleConnection *gc; char *err; if (user == NULL) return; if (ret_code == NM_OK) { rc = nm_send_conference_invite(user, conference, user_record, NULL, _sendinvite_resp_cb, NULL); _check_for_disconnect(user, rc); } else { err = g_strdup_printf(_("Unable to create conference (%s)."), nm_error_to_string(ret_code)); gc = purple_account_get_connection(user->client_data); purple_notify_error(gc, NULL, err, NULL); g_free(err); } } /******************************************************************************* * Helper functions ******************************************************************************/ static char * _user_agent_string() { #if !defined(_WIN32) const char *sysname = ""; const char *release = ""; struct utsname u; if (uname(&u) == 0) { sysname = u.sysname; release = u.release; } else { sysname = "Linux"; release = "Unknown"; } return g_strdup_printf("Purple/%s (%s; %s)", VERSION, sysname, release); #else const char *sysname = ""; OSVERSIONINFO os_info; SYSTEM_INFO sys_info; os_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&os_info); GetSystemInfo(&sys_info); if (os_info.dwPlatformId == VER_PLATFORM_WIN32_NT) { switch (os_info.dwMajorVersion) { case 3: case 4: sysname = "Windows NT"; break; case 5: switch (os_info.dwMinorVersion) { case 0: sysname = "Windows 2000"; break; case 1: sysname = "Windows XP"; break; case 2: sysname = "Windows Server 2003"; break; default: sysname = "Windows"; break; } break; default: sysname = "Windows"; break; } } else if (os_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { switch (os_info.dwMinorVersion) { case 0: sysname = "Windows 95"; break; case 10: sysname = "Windows 98"; break; case 90: sysname = "Windows ME"; break; default: sysname = "Windows"; break; } } else { sysname = "Windows"; } return g_strdup_printf("Purple/%s (%s; %ld.%ld)", VERSION, sysname, os_info.dwMajorVersion, os_info.dwMinorVersion); #endif } static gboolean _is_disconnect_error(NMERR_T err) { return (err == NMERR_TCP_WRITE || err == NMERR_TCP_READ || err == NMERR_PROTOCOL); } static gboolean _check_for_disconnect(NMUser * user, NMERR_T err) { PurpleConnection *gc = purple_account_get_connection(user->client_data); if (_is_disconnect_error(err)) { purple_connection_error(gc, _("Error communicating with server." " Closing connection.")); return TRUE; } return FALSE; } /* Check to see if the conference is instantiated, if so send the message. * If not send the create conference -- the response handler for the createconf * will call this function again. */ static void _send_message(NMUser * user, NMMessage * message) { NMConference *conf; NMERR_T rc = NM_OK; conf = nm_message_get_conference(message); if (conf) { /* We have a conference make sure that the server knows about it already. */ if (nm_conference_is_instantiated(conf)) { /* We have everything that we need...finally! */ rc = nm_send_message(user, message, _send_message_resp_cb); _check_for_disconnect(user, rc); nm_release_message(message); } else { rc = nm_send_create_conference(user, conf, _createconf_resp_send_msg, message); _check_for_disconnect(user, rc); } } } /* * Update the status of the given buddy in the Purple buddy list */ static void _update_buddy_status(NMUser *user, PurpleBuddy * buddy, int novellstatus, int gmt) { PurpleAccount *account; const char *status_id; const char *text = NULL; const char *dn; int idle = 0; gboolean loggedin = TRUE; account = buddy->account; switch (novellstatus) { case NM_STATUS_AVAILABLE: status_id = NOVELL_STATUS_TYPE_AVAILABLE; break; case NM_STATUS_AWAY: status_id = NOVELL_STATUS_TYPE_AWAY; break; case NM_STATUS_BUSY: status_id = NOVELL_STATUS_TYPE_BUSY; break; case NM_STATUS_OFFLINE: status_id = NOVELL_STATUS_TYPE_OFFLINE; loggedin = FALSE; break; case NM_STATUS_AWAY_IDLE: status_id = NOVELL_STATUS_TYPE_AWAY; idle = gmt; break; default: status_id = NOVELL_STATUS_TYPE_OFFLINE; loggedin = FALSE; break; } /* Get status text for the user */ dn = nm_lookup_dn(user, buddy->name); if (dn) { NMUserRecord *user_record = nm_find_user_record(user, dn); if (user_record) { text = nm_user_record_get_status_text(user_record); } } purple_prpl_got_user_status(account, buddy->name, status_id, "message", text, NULL); purple_prpl_got_user_idle(account, buddy->name, (novellstatus == NM_STATUS_AWAY_IDLE), idle); } /* Iterate through the cached Purple buddy list and remove buddies * that are not in the server side list. */ static void _remove_purple_buddies(NMUser *user) { PurpleBlistNode *gnode; PurpleBlistNode *cnode; PurpleBlistNode *bnode; PurpleGroup *group; PurpleBuddy *buddy; PurpleBuddyList *blist; GSList *rem_list = NULL; GSList *l; NMFolder *folder = NULL; const char *gname = NULL; if ((blist = purple_get_blist())) { for (gnode = blist->root; gnode; gnode = gnode->next) { if (!PURPLE_BLIST_NODE_IS_GROUP(gnode)) continue; group = (PurpleGroup *) gnode; for (cnode = gnode->child; cnode; cnode = cnode->next) { if (!PURPLE_BLIST_NODE_IS_CONTACT(cnode)) continue; for (bnode = cnode->child; bnode; bnode = bnode->next) { if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode)) continue; buddy = (PurpleBuddy *) bnode; if (buddy->account == user->client_data) { gname = group->name; if (strcmp(group->name, NM_ROOT_FOLDER_NAME) == 0) gname = ""; folder = nm_find_folder(user, gname); if (folder == NULL || !nm_folder_find_contact_by_display_id(folder, buddy->name)) { rem_list = g_slist_append(rem_list, buddy); } } } } } if (rem_list) { for (l = rem_list; l; l = l->next) { purple_blist_remove_buddy(l->data); } g_slist_free(rem_list); } } } /* Add all of the contacts in the given folder to the Purple buddy list */ static void _add_contacts_to_purple_blist(NMUser * user, NMFolder * folder) { NMUserRecord *user_record = NULL; NMContact *contact = NULL; PurpleBuddy *buddy = NULL; PurpleGroup *group; NMERR_T cnt = 0, i; const char *text = NULL; const char *name = NULL; const char *fname = NULL; int status = 0; /* If this is the root folder give it a name. Purple does not have the concept of * a root folder. */ fname = nm_folder_get_name(folder); if (fname == NULL || *fname == '\0') { fname = NM_ROOT_FOLDER_NAME; } /* Does the Purple group exist already? */ group = purple_find_group(fname); if (group == NULL) { group = purple_group_new(fname); purple_blist_add_group(group, NULL); } /* Get each contact for this folder */ cnt = nm_folder_get_contact_count(folder); for (i = 0; i < cnt; i++) { contact = nm_folder_get_contact(folder, i); if (contact) { name = nm_contact_get_display_id(contact); if (name) { buddy = purple_find_buddy_in_group(user->client_data, name, group); if (buddy == NULL) { /* Add it to the purple buddy list */ buddy = purple_buddy_new(user->client_data, name, nm_contact_get_display_name(contact)); purple_blist_add_buddy(buddy, NULL, group, NULL); } /* Set the initial status for the buddy */ user_record = nm_contact_get_user_record(contact); if (user_record) { status = nm_user_record_get_status(user_record); text = nm_user_record_get_status_text(user_record); } _update_buddy_status(user, buddy, status, time(0)); /* Save the new buddy as part of the contact object */ nm_contact_set_data(contact, (gpointer) buddy); } } else { /* NULL contact. This should not happen, but * let's break out of the loop. */ break; } } } /* Add all of the server side contacts to the Purple buddy list. */ static void _add_purple_buddies(NMUser * user) { int cnt = 0, i; NMFolder *root_folder = NULL; NMFolder *folder = NULL; root_folder = nm_get_root_folder(user); if (root_folder) { /* Add sub-folders and contacts to sub-folders... * iterate throught the sub-folders in reverse order * because Purple adds the folders to the front -- so we * want to add the first folder last */ cnt = nm_folder_get_subfolder_count(root_folder); for (i = cnt-1; i >= 0; i--) { folder = nm_folder_get_subfolder(root_folder, i); if (folder) { _add_contacts_to_purple_blist(user, folder); } } /* Add contacts for the root folder */ _add_contacts_to_purple_blist(user, root_folder); } } static void _sync_contact_list(NMUser *user) { /* Remove all buddies from the local list that are * not in the server side list and add all buddies * from the server side list that are not in * the local list */ _remove_purple_buddies(user); _add_purple_buddies(user); user->clist_synched = TRUE; } static void _sync_privacy_lists(NMUser *user) { GSList *node = NULL, *rem_list = NULL; PurpleConnection *gc; const char *name, *dn; NMUserRecord *user_record; if (user == NULL) return; gc = purple_account_get_connection(user->client_data); if (gc == NULL) return; /* Set the Purple privacy setting */ if (user->default_deny) { if (user->allow_list == NULL) { gc->account->perm_deny = PURPLE_PRIVACY_DENY_ALL; } else { gc->account->perm_deny = PURPLE_PRIVACY_ALLOW_USERS; } } else { if (user->deny_list == NULL) { gc->account->perm_deny = PURPLE_PRIVACY_ALLOW_ALL; } else { gc->account->perm_deny = PURPLE_PRIVACY_DENY_USERS; } } /* Add stuff */ for (node = user->allow_list; node; node = node->next) { user_record = nm_find_user_record(user, (char *)node->data); if (user_record) name = nm_user_record_get_display_id(user_record); else name =(char *)node->data; if (!g_slist_find_custom(gc->account->permit, name, (GCompareFunc)purple_utf8_strcasecmp)) { purple_privacy_permit_add(gc->account, name , TRUE); } } for (node = user->deny_list; node; node = node->next) { user_record = nm_find_user_record(user, (char *)node->data); if (user_record) name = nm_user_record_get_display_id(user_record); else name =(char *)node->data; if (!g_slist_find_custom(gc->account->deny, name, (GCompareFunc)purple_utf8_strcasecmp)) { purple_privacy_deny_add(gc->account, name, TRUE); } } /* Remove stuff */ for (node = gc->account->permit; node; node = node->next) { dn = nm_lookup_dn(user, (char *)node->data); if (dn != NULL && !g_slist_find_custom(user->allow_list, dn, (GCompareFunc)purple_utf8_strcasecmp)) { rem_list = g_slist_append(rem_list, node->data); } } if (rem_list) { for (node = rem_list; node; node = node->next) { purple_privacy_permit_remove(gc->account, (char *)node->data, TRUE); } g_free(rem_list); rem_list = NULL; } for (node = gc->account->deny; node; node = node->next) { dn = nm_lookup_dn(user, (char *)node->data); if (dn != NULL && !g_slist_find_custom(user->deny_list, dn, (GCompareFunc)purple_utf8_strcasecmp)) { rem_list = g_slist_append(rem_list, node->data); } } if (rem_list) { for (node = rem_list; node; node = node->next) { purple_privacy_deny_remove(gc->account, (char *)node->data, TRUE); } g_slist_free(rem_list); } } /* Map known property tags to user-friendly strings */ static const char * _map_property_tag(const char *tag) { if (tag == NULL) return NULL; if (strcmp(tag, "telephoneNumber") == 0) return _("Telephone Number"); else if (strcmp(tag, "L") == 0) return _("Location"); else if (strcmp(tag, "OU") == 0) return _("Department"); else if (strcmp(tag, "personalTitle") == 0) return _("Personal Title"); else if (strcmp(tag, "Title") == 0) return _("Title"); else if (strcmp(tag, "mailstop") == 0) return _("Mailstop"); else if (strcmp(tag, "Internet EMail Address") == 0) return _("E-Mail Address"); else return tag; } /* Display a dialog box showing the properties for the given user record */ static void _show_info(PurpleConnection * gc, NMUserRecord * user_record) { PurpleNotifyUserInfo *user_info = purple_notify_user_info_new(); int count, i; NMProperty *property; const char *tag, *value; tag = _("User ID"); value = nm_user_record_get_userid(user_record); if (value) { purple_notify_user_info_add_pair(user_info, tag, value); } /* tag = _("DN"); value = nm_user_record_get_dn(user_record); if (value) { purple_notify_user_info_add_pair(user_info, tag, value); } */ tag = _("Full name"); value = nm_user_record_get_full_name(user_record); if (value) { purple_notify_user_info_add_pair(user_info, tag, value); } count = nm_user_record_get_property_count(user_record); for (i = 0; i < count; i++) { property = nm_user_record_get_property(user_record, i); if (property) { tag = _map_property_tag(nm_property_get_tag(property)); value = nm_property_get_value(property); if (tag && value) { purple_notify_user_info_add_pair(user_info, tag, value); } nm_release_property(property); } } purple_notify_userinfo(gc, nm_user_record_get_userid(user_record), user_info, NULL, NULL); purple_notify_user_info_destroy(user_info); } /* Send a join conference, the first item in the parms list is the * NMUser object and the second item is the conference to join. * This callback is passed to purple_request_action when we ask the * user if they want to join the conference. */ static void _join_conference_cb(GSList * parms) { NMUser *user; NMConference *conference; NMERR_T rc = NM_OK; if (parms == NULL || g_slist_length(parms) != 2) return; user = g_slist_nth_data(parms, 0); conference = g_slist_nth_data(parms, 1); if (user && conference) { rc = nm_send_join_conference(user, conference, _join_conf_resp_cb, conference); _check_for_disconnect(user, rc); } g_slist_free(parms); } /* Send a reject conference, the first item in the parms list is the * NMUser object and the second item is the conference to reject. * This callback is passed to purple_request_action when we ask the * user if they want to joing the conference. */ static void _reject_conference_cb(GSList * parms) { NMUser *user; NMConference *conference; NMERR_T rc = NM_OK; if (parms == NULL || g_slist_length(parms) != 2) return; user = g_slist_nth_data(parms, 0); conference = g_slist_nth_data(parms, 1); if (user && conference) { rc = nm_send_reject_conference(user, conference, NULL, NULL); _check_for_disconnect(user, rc); } g_slist_free(parms); } static void _initiate_conference_cb(PurpleBlistNode *node, gpointer ignored) { PurpleBuddy *buddy; PurpleConnection *gc; NMUser *user; const char *conf_name; PurpleConversation *chat = NULL; NMUserRecord *user_record; NMConference *conference; g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node)); buddy = (PurpleBuddy *) node; gc = purple_account_get_connection(buddy->account); user = gc->proto_data; if (user == NULL) return; /* We should already have a userrecord for the buddy */ user_record = nm_find_user_record(user, buddy->name); if (user_record == NULL) return; conf_name = _get_conference_name(++user->conference_count); chat = serv_got_joined_chat(gc, user->conference_count, conf_name); if (chat) { conference = nm_create_conference(NULL); nm_conference_set_data(conference, (gpointer) chat); nm_send_create_conference(user, conference, _createconf_resp_send_invite, user_record); nm_release_conference(conference); } } const char * _get_conference_name(int id) { static char *name = NULL; if (name) g_free(name); name = g_strdup_printf(_("GroupWise Conference %d"), id); return name; } static void _show_privacy_locked_error(PurpleConnection *gc, NMUser *user) { char *err; err = g_strdup_printf(_("Unable to change server side privacy settings (%s)."), nm_error_to_string(NMERR_ADMIN_LOCKED)); purple_notify_error(gc, NULL, err, NULL); g_free(err); } /******************************************************************************* * Connect and recv callbacks ******************************************************************************/ static void novell_ssl_connect_error(PurpleSslConnection * gsc, PurpleSslErrorType error, gpointer data) { PurpleConnection *gc; NMUser *user; gc = data; user = gc->proto_data; user->conn->ssl_conn->data = NULL; purple_connection_error(gc, _("Unable to make SSL connection to server.")); } static void novell_ssl_recv_cb(gpointer data, PurpleSslConnection * gsc, PurpleInputCondition condition) { PurpleConnection *gc = data; NMUser *user; NMERR_T rc; if (gc == NULL) return; user = gc->proto_data; if (user == NULL) return; rc = nm_process_new_data(user); if (rc != NM_OK) { if (_is_disconnect_error(rc)) { purple_connection_error(gc, _("Error communicating with server." " Closing connection.")); } else { purple_debug(PURPLE_DEBUG_INFO, "novell", "Error processing event or response (%d).\n", rc); } } } static void novell_ssl_connected_cb(gpointer data, PurpleSslConnection * gsc, PurpleInputCondition cond) { PurpleConnection *gc = data; NMUser *user; NMConn *conn; NMERR_T rc = 0; const char *pwd = NULL; const char *my_addr = NULL; char *ua = NULL; if (gc == NULL || gsc == NULL) return; user = gc->proto_data; if ((user == NULL) || (conn = user->conn) == NULL) return; purple_connection_update_progress(gc, _("Authenticating..."), 2, NOVELL_CONNECT_STEPS); my_addr = purple_network_get_my_ip(gsc->fd); pwd = purple_connection_get_password(gc); ua = _user_agent_string(); rc = nm_send_login(user, pwd, my_addr, ua, _login_resp_cb, NULL); if (rc == NM_OK) { conn->connected = TRUE; purple_ssl_input_add(gsc, novell_ssl_recv_cb, gc); } else { purple_connection_error(gc, _("Unable to connect to server.")); } purple_connection_update_progress(gc, _("Waiting for response..."), 3, NOVELL_CONNECT_STEPS); g_free(ua); } /******************************************************************************* * Event callback and event handlers ******************************************************************************/ static void _evt_receive_message(NMUser * user, NMEvent * event) { NMUserRecord *user_record = NULL; NMContact *contact = NULL; PurpleConversation *gconv; NMConference *conference; PurpleMessageFlags flags; char *text = NULL; text = g_markup_escape_text(nm_event_get_text(event), -1); conference = nm_event_get_conference(event); if (conference) { PurpleConversation *chat = nm_conference_get_data(conference); /* Is this a single person 'conversation' or a conference? */ if (chat == NULL && nm_conference_get_participant_count(conference) == 1) { user_record = nm_find_user_record(user, nm_event_get_source(event)); if (user_record) { flags = 0; if (nm_event_get_type(event) == NMEVT_RECEIVE_AUTOREPLY) flags |= PURPLE_MESSAGE_AUTO_RESP; serv_got_im(purple_account_get_connection(user->client_data), nm_user_record_get_display_id(user_record), text, flags, nm_event_get_gmt(event)); gconv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, nm_user_record_get_display_id(user_record), (PurpleAccount *) user->client_data); if (gconv) { contact = nm_find_contact(user, nm_event_get_source(event)); if (contact) { purple_conversation_set_title( gconv, nm_contact_get_display_name(contact)); } else { const char *name = nm_user_record_get_full_name(user_record); if (name == NULL) name = nm_user_record_get_userid(user_record); purple_conversation_set_title(gconv, name); } } } else { /* this should not happen, see the event code. * the event code will get the contact details from * the server if it does not have them before calling * the event callback. */ } } else if (chat) { /* get the contact for send if we have one */ NMContact *contact = nm_find_contact(user, nm_event_get_source(event)); /* get the user record for the sender */ user_record = nm_find_user_record(user, nm_event_get_source(event)); if (user_record) { const char *name = nm_contact_get_display_name(contact); if (name == NULL) { name = nm_user_record_get_full_name(user_record); if (name == NULL) name = nm_user_record_get_display_id(user_record); } serv_got_chat_in(purple_account_get_connection(user->client_data), purple_conv_chat_get_id(PURPLE_CONV_CHAT(chat)), name, 0, text, nm_event_get_gmt(event)); } } } g_free(text); } static void _evt_conference_left(NMUser * user, NMEvent * event) { PurpleConversation *chat; NMConference *conference; conference = nm_event_get_conference(event); if (conference) { chat = nm_conference_get_data(conference); if (chat) { NMUserRecord *ur = nm_find_user_record(user, nm_event_get_source(event)); if (ur) purple_conv_chat_remove_user(PURPLE_CONV_CHAT(chat), nm_user_record_get_display_id(ur), NULL); } } } static void _evt_conference_invite_notify(NMUser * user, NMEvent * event) { PurpleConversation *gconv; NMConference *conference; NMUserRecord *user_record = NULL; char *str = NULL; user_record = nm_find_user_record(user, nm_event_get_source(event)); conference = nm_event_get_conference(event); if (user_record && conference) { gconv = nm_conference_get_data(conference); str = g_strdup_printf(_("%s has been invited to this conversation."), nm_user_record_get_display_id(user_record)); purple_conversation_write(gconv, NULL, str, PURPLE_MESSAGE_SYSTEM, time(NULL)); g_free(str); } } static void _evt_conference_invite(NMUser * user, NMEvent * event) { NMUserRecord *ur; PurpleConnection *gc; GSList *parms = NULL; const char *title = NULL; const char *secondary = NULL; const char *name = NULL; char *primary = NULL; time_t gmt; ur = nm_find_user_record(user, nm_event_get_source(event)); if (ur) name = nm_user_record_get_full_name(ur); if (name == NULL) name = nm_event_get_source(event); gmt = nm_event_get_gmt(event); title = _("Invitation to Conversation"); primary = g_strdup_printf(_("Invitation from: %s\n\nSent: %s"), name, purple_date_format_full(localtime(&gmt))); secondary = _("Would you like to join the conversation?"); /* Set up parms list for the callbacks * We need to send the NMUser object and * the NMConference object to the callbacks */ parms = NULL; parms = g_slist_append(parms, user); parms = g_slist_append(parms, nm_event_get_conference(event)); /* Prompt the user */ gc = purple_account_get_connection(user->client_data); purple_request_action(gc, title, primary, secondary, PURPLE_DEFAULT_ACTION_NONE, purple_connection_get_account(gc), name, NULL, parms, 2, _("Yes"), G_CALLBACK(_join_conference_cb), _("No"), G_CALLBACK(_reject_conference_cb)); g_free(primary); } static void _evt_conference_joined(NMUser * user, NMEvent * event) { PurpleConversation *chat = NULL; PurpleConnection *gc; NMConference *conference = NULL; NMUserRecord *ur = NULL; const char *name; const char *conf_name; gc = purple_account_get_connection(user->client_data); if (gc == NULL) return; conference = nm_event_get_conference(event); if (conference) { chat = nm_conference_get_data(conference); if (nm_conference_get_participant_count(conference) == 2 && chat == NULL) { ur = nm_conference_get_participant(conference, 0); if (ur) { conf_name = _get_conference_name(++user->conference_count); chat = serv_got_joined_chat(gc, user->conference_count, conf_name); if (chat) { nm_conference_set_data(conference, (gpointer) chat); name = nm_user_record_get_display_id(ur); purple_conv_chat_add_user(PURPLE_CONV_CHAT(chat), name, NULL, PURPLE_CBFLAGS_NONE, TRUE); } } } if (chat != NULL) { ur = nm_find_user_record(user, nm_event_get_source(event)); if (ur) { name = nm_user_record_get_display_id(ur); if (!purple_conv_chat_find_user(PURPLE_CONV_CHAT(chat), name)) { purple_conv_chat_add_user(PURPLE_CONV_CHAT(chat), name, NULL, PURPLE_CBFLAGS_NONE, TRUE); } } } } } static void _evt_status_change(NMUser * user, NMEvent * event) { PurpleBuddy *buddy = NULL; GSList *buddies; GSList *bnode; NMUserRecord *user_record; const char *display_id; int status; user_record = nm_event_get_user_record(event); if (user_record) { /* Retrieve new status */ status = nm_user_record_get_status(user_record); /* Update status for buddy in all folders */ display_id = nm_user_record_get_display_id(user_record); buddies = purple_find_buddies(user->client_data, display_id); for (bnode = buddies; bnode; bnode = bnode->next) { buddy = (PurpleBuddy *) bnode->data; if (buddy) { _update_buddy_status(user, buddy, status, nm_event_get_gmt(event)); } } g_slist_free(buddies); } } static void _evt_user_disconnect(NMUser * user, NMEvent * event) { PurpleConnection *gc; gc = purple_account_get_connection((PurpleAccount *) user->client_data); if (gc) { gc->wants_to_die = TRUE; /* we don't want to reconnect in this case */ purple_connection_error(gc, _("You have been logged out because you" " logged in at another workstation.")); } } static void _evt_user_typing(NMUser * user, NMEvent * event) { PurpleConnection *gc; NMUserRecord *user_record = NULL; gc = purple_account_get_connection((PurpleAccount *) user->client_data); if (gc) { user_record = nm_find_user_record(user, nm_event_get_source(event)); if (user_record) { serv_got_typing(gc, nm_user_record_get_display_id(user_record), 30, PURPLE_TYPING); } } } static void _evt_user_not_typing(NMUser * user, NMEvent * event) { PurpleConnection *gc; NMUserRecord *user_record; gc = purple_account_get_connection((PurpleAccount *) user->client_data); if (gc) { user_record = nm_find_user_record(user, nm_event_get_source(event)); if (user_record) { serv_got_typing_stopped(gc, nm_user_record_get_display_id(user_record)); } } } static void _evt_undeliverable_status(NMUser * user, NMEvent * event) { NMUserRecord *ur; PurpleConversation *gconv; char *str; ur = nm_find_user_record(user, nm_event_get_source(event)); if (ur) { /* XXX - Should this be PURPLE_CONV_TYPE_IM? */ gconv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, nm_user_record_get_display_id(ur), user->client_data); if (gconv) { const char *name = nm_user_record_get_full_name(ur); if (name == NULL) { name = nm_user_record_get_display_id(ur); } str = g_strdup_printf(_("%s appears to be offline and did not receive" " the message that you just sent."), name); purple_conversation_write(gconv, NULL, str, PURPLE_MESSAGE_SYSTEM, time(NULL)); g_free(str); } } } static void _event_callback(NMUser * user, NMEvent * event) { if (user == NULL || event == NULL) return; switch (nm_event_get_type(event)) { case NMEVT_STATUS_CHANGE: _evt_status_change(user, event); break; case NMEVT_RECEIVE_AUTOREPLY: case NMEVT_RECEIVE_MESSAGE: _evt_receive_message(user, event); break; case NMEVT_USER_DISCONNECT: _evt_user_disconnect(user, event); break; case NMEVT_USER_TYPING: _evt_user_typing(user, event); break; case NMEVT_USER_NOT_TYPING: _evt_user_not_typing(user, event); break; case NMEVT_SERVER_DISCONNECT: /* Nothing to do? */ break; case NMEVT_INVALID_RECIPIENT: break; case NMEVT_UNDELIVERABLE_STATUS: _evt_undeliverable_status(user, event); break; case NMEVT_CONFERENCE_INVITE_NOTIFY: /* Someone else has been invited to join a * conference that we are currently a part of */ _evt_conference_invite_notify(user, event); break; case NMEVT_CONFERENCE_INVITE: /* We have been invited to join a conference */ _evt_conference_invite(user, event); break; case NMEVT_CONFERENCE_JOINED: /* Some one has joined a conference that we * are a part of */ _evt_conference_joined(user, event); break; case NMEVT_CONFERENCE_LEFT: /* Someone else has left a conference that we * are currently a part of */ _evt_conference_left(user, event); break; default: purple_debug(PURPLE_DEBUG_INFO, "novell", "_event_callback(): unhandled event, %d\n", nm_event_get_type(event)); break; } } /******************************************************************************* * Prpl Ops ******************************************************************************/ static void novell_login(PurpleAccount * account) { PurpleConnection *gc; NMUser *user = NULL; const char *server; const char *name; int port; if (account == NULL) return; gc = purple_account_get_connection(account); if (gc == NULL) return; server = purple_account_get_string(account, "server", NULL); if (server == NULL || *server == '\0') { /* TODO: Would be nice to prompt if not set! * purple_request_fields(gc, _("Server Address"),...); */ /* ...but for now just error out with a nice message. */ purple_connection_error(gc, _("Unable to connect to server." " Please enter the address of the server" " you wish to connect to.")); return; } port = purple_account_get_int(account, "port", DEFAULT_PORT); name = purple_account_get_username(account); user = nm_initialize_user(name, server, port, account, _event_callback); if (user && user->conn) { /* save user */ gc->proto_data = user; /* connect to the server */ purple_connection_update_progress(gc, _("Connecting"), 1, NOVELL_CONNECT_STEPS); user->conn->use_ssl = TRUE; user->conn->ssl_conn = g_new0(NMSSLConn, 1); user->conn->ssl_conn->read = (nm_ssl_read_cb) purple_ssl_read; user->conn->ssl_conn->write = (nm_ssl_write_cb) purple_ssl_write; user->conn->ssl_conn->data = purple_ssl_connect(user->client_data, user->conn->addr, user->conn->port, novell_ssl_connected_cb, novell_ssl_connect_error, gc); if (user->conn->ssl_conn->data == NULL) { purple_connection_error(gc, _("Error." " SSL support is not installed.")); } } } static void novell_close(PurpleConnection * gc) { NMUser *user; NMConn *conn; if (gc == NULL) return; user = gc->proto_data; if (user) { conn = user->conn; if (conn && conn->ssl_conn) { purple_ssl_close(user->conn->ssl_conn->data); } nm_deinitialize_user(user); } gc->proto_data = NULL; } static int novell_send_im(PurpleConnection * gc, const char *name, const char *message_body, PurpleMessageFlags flags) { NMUserRecord *user_record = NULL; NMConference *conf = NULL; NMMessage *message; NMUser *user; const char *dn = NULL; char *plain; gboolean done = TRUE, created_conf = FALSE; NMERR_T rc = NM_OK; if (gc == NULL || name == NULL || message_body == NULL || *message_body == '\0') return 0; user = gc->proto_data; if (user == NULL) return 0; /* Create a new message */ plain = purple_unescape_html(message_body); message = nm_create_message(plain); g_free(plain); /* Need to get the DN for the buddy so we can look up the convo */ dn = nm_lookup_dn(user, name); /* Do we already know about the sender? */ user_record = nm_find_user_record(user, dn); if (user_record) { /* Do we already have an instantiated conference? */ conf = nm_find_conversation(user, dn); if (conf == NULL) { /* If not, create a blank conference */ conf = nm_create_conference(NULL); created_conf = TRUE; nm_conference_add_participant(conf, user_record); } nm_message_set_conference(message, conf); /* Make sure conference is instantiated */ if (!nm_conference_is_instantiated(conf)) { /* It is not, so send the createconf. We will * have to finish sending the message when we * get the response with the new conference guid. */ rc = nm_send_create_conference(user, conf, _createconf_resp_send_msg, message); _check_for_disconnect(user, rc); done = FALSE; } } else { /* If we don't have details for the user, then we don't have * a conference yet. So create one and send the getdetails * to the server. We will have to finish sending the message * when we get the response from the server. */ conf = nm_create_conference(NULL); created_conf = TRUE; nm_message_set_conference(message, conf); rc = nm_send_get_details(user, name, _get_details_resp_send_msg, message); _check_for_disconnect(user, rc); done = FALSE; } if (done) { /* Did we find everything we needed? */ rc = nm_send_message(user, message, _send_message_resp_cb); _check_for_disconnect(user, rc); nm_release_message(message); } if (created_conf && conf) nm_release_conference(conf); return 1; } static unsigned int novell_send_typing(PurpleConnection * gc, const char *name, PurpleTypingState state) { NMConference *conf = NULL; NMUser *user; const char *dn = NULL; NMERR_T rc = NM_OK; if (gc == NULL || name == NULL) return 0; user = gc->proto_data; if (user == NULL) return 0; /* Need to get the DN for the buddy so we can look up the convo */ dn = nm_lookup_dn(user, name); if (dn) { /* Now find the conference in our list */ conf = nm_find_conversation(user, dn); if (conf) { rc = nm_send_typing(user, conf, ((state == PURPLE_TYPING) ? TRUE : FALSE), NULL); _check_for_disconnect(user, rc); } } return 0; } static void novell_convo_closed(PurpleConnection * gc, const char *who) { NMUser *user; NMConference *conf; const char *dn; NMERR_T rc = NM_OK; if (gc == NULL || who == NULL) return; user = gc->proto_data; if (user && (dn = nm_lookup_dn(user, who))) { conf = nm_find_conversation(user, dn); if (conf) { rc = nm_send_leave_conference(user, conf, NULL, NULL); _check_for_disconnect(user, rc); } } } static void novell_chat_leave(PurpleConnection * gc, int id) { NMConference *conference; NMUser *user; PurpleConversation *chat; GSList *cnode; NMERR_T rc = NM_OK; if (gc == NULL) return; user = gc->proto_data; if (user == NULL) return; for (cnode = user->conferences; cnode != NULL; cnode = cnode->next) { conference = cnode->data; if (conference && (chat = nm_conference_get_data(conference))) { if (purple_conv_chat_get_id(PURPLE_CONV_CHAT(chat)) == id) { rc = nm_send_leave_conference(user, conference, NULL, NULL); _check_for_disconnect(user, rc); break; } } } serv_got_chat_left(gc, id); } static void novell_chat_invite(PurpleConnection *gc, int id, const char *message, const char *who) { NMConference *conference; NMUser *user; PurpleConversation *chat; GSList *cnode; NMERR_T rc = NM_OK; NMUserRecord *user_record = NULL; if (gc == NULL) return; user = gc->proto_data; if (user == NULL) return; user_record = nm_find_user_record(user, who); if (user_record == NULL) { rc = nm_send_get_details(user, who, _get_details_resp_send_invite, GINT_TO_POINTER(id)); _check_for_disconnect(user, rc); return; } for (cnode = user->conferences; cnode != NULL; cnode = cnode->next) { conference = cnode->data; if (conference && (chat = nm_conference_get_data(conference))) { if (purple_conv_chat_get_id(PURPLE_CONV_CHAT(chat)) == id) { rc = nm_send_conference_invite(user, conference, user_record, message, _sendinvite_resp_cb, NULL); _check_for_disconnect(user, rc); break; } } } } static int novell_chat_send(PurpleConnection * gc, int id, const char *text, PurpleMessageFlags flags) { NMConference *conference; PurpleConversation *chat; GSList *cnode; NMMessage *message; NMUser *user; NMERR_T rc = NM_OK; const char *name; char *str, *plain; if (gc == NULL || text == NULL) return -1; user = gc->proto_data; if (user == NULL) return -1; plain = purple_unescape_html(text); message = nm_create_message(plain); g_free(plain); for (cnode = user->conferences; cnode != NULL; cnode = cnode->next) { conference = cnode->data; if (conference && (chat = nm_conference_get_data(conference))) { if (purple_conv_chat_get_id(PURPLE_CONV_CHAT(chat)) == id) { nm_message_set_conference(message, conference); /* check to see if the conference is instatiated yet */ if (!nm_conference_is_instantiated(conference)) { nm_message_add_ref(message); nm_send_create_conference(user, conference, _createconf_resp_send_msg, message); } else { rc = nm_send_message(user, message, _send_message_resp_cb); } nm_release_message(message); if (!_check_for_disconnect(user, rc)) { /* Use the account alias if it is set */ name = purple_account_get_alias(user->client_data); if (name == NULL || *name == '\0') { /* If there is no account alias, try full name */ name = nm_user_record_get_full_name(user->user_record); if (name == NULL || *name == '\0') { /* Fall back to the username that we are signed in with */ name = purple_account_get_username(user->client_data); } } serv_got_chat_in(gc, id, name, 0, text, time(NULL)); return 0; } else return -1; } } } /* The conference was not found, must be closed */ chat = purple_find_chat(gc, id); if (chat) { str = g_strdup_printf(_("This conference has been closed." " No more messages can be sent.")); purple_conversation_write(chat, NULL, str, PURPLE_MESSAGE_SYSTEM, time(NULL)); g_free(str); } if (message) nm_release_message(message); return -1; } static void novell_add_buddy(PurpleConnection * gc, PurpleBuddy *buddy, PurpleGroup * group) { NMFolder *folder = NULL; NMContact *contact; NMUser *user; NMERR_T rc = NM_OK; const char *alias, *gname; if (gc == NULL || buddy == NULL || group == NULL) return; user = (NMUser *) gc->proto_data; if (user == NULL) return; /* If we haven't synched the contact list yet, ignore * the add_buddy calls. Server side list is the master. */ if (!user->clist_synched) return; contact = nm_create_contact(); nm_contact_set_dn(contact, buddy->name); /* Remove the PurpleBuddy (we will add it back after adding it * to the server side list). Save the alias if there is one. */ alias = purple_buddy_get_alias(buddy); if (alias && strcmp(alias, buddy->name)) nm_contact_set_display_name(contact, alias); purple_blist_remove_buddy(buddy); buddy = NULL; if (strcmp(group->name, NM_ROOT_FOLDER_NAME) == 0) { gname = ""; } else { gname = group->name; } folder = nm_find_folder(user, gname); if (folder) { /* We have everything that we need, so send the createcontact */ rc = nm_send_create_contact(user, folder, contact, _create_contact_resp_cb, contact); } else { /* Need to create the folder before we can add the contact */ rc = nm_send_create_folder(user, gname, _create_folder_resp_add_contact, contact); } _check_for_disconnect(user, rc); } static void novell_remove_buddy(PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) { NMContact *contact; NMFolder *folder; NMUser *user; const char *dn, *gname; NMERR_T rc = NM_OK; if (gc == NULL || buddy == NULL || group == NULL) return; user = (NMUser *) gc->proto_data; if (user && (dn = nm_lookup_dn(user, buddy->name))) { if (strcmp(group->name, NM_ROOT_FOLDER_NAME) == 0) { gname = ""; } else { gname = group->name; } folder = nm_find_folder(user, gname); if (folder) { contact = nm_folder_find_contact(folder, dn); if (contact) { /* Remove the buddy from the contact */ nm_contact_set_data(contact, NULL); /* Tell the server to remove the contact */ rc = nm_send_remove_contact(user, folder, contact, _remove_contact_resp_cb, NULL); _check_for_disconnect(user, rc); } } } } static void novell_remove_group(PurpleConnection * gc, PurpleGroup *group) { NMUser *user; NMERR_T rc = NM_OK; if (gc == NULL || group == NULL) return; user = (NMUser *) gc->proto_data; if (user) { NMFolder *folder = nm_find_folder(user, group->name); if (folder) { rc = nm_send_remove_folder(user, folder, _remove_folder_resp_cb, NULL); _check_for_disconnect(user, rc); } } } static void novell_alias_buddy(PurpleConnection * gc, const char *name, const char *alias) { NMContact *contact; NMUser *user; GList *contacts = NULL; GList *cnode = NULL; const char *dn = NULL, *fname = NULL; NMERR_T rc = NM_OK; if (gc == NULL || name == NULL || alias == NULL) return; user = (NMUser *) gc->proto_data; if (user && (dn = nm_lookup_dn(user, name))) { /* Alias all of instances of the contact */ contacts = nm_find_contacts(user, dn); for (cnode = contacts; cnode != NULL; cnode = cnode->next) { contact = (NMContact *) cnode->data; if (contact) { PurpleGroup *group = NULL; PurpleBuddy *buddy; NMFolder *folder; /* Alias the Purple buddy? */ folder = nm_find_folder_by_id(user, nm_contact_get_parent_id(contact)); if (folder) { fname = nm_folder_get_name(folder); if (*fname == '\0') { fname = NM_ROOT_FOLDER_NAME; } group = purple_find_group(fname); } if (group) { buddy = purple_find_buddy_in_group(user->client_data, name, group); if (buddy && strcmp(buddy->alias, alias)) purple_blist_alias_buddy(buddy, alias); } /* Tell the server to alias the contact */ rc = nm_send_rename_contact(user, contact, alias, _rename_contact_resp_cb, NULL); _check_for_disconnect(user, rc); } } if (contacts) g_list_free(contacts); } } static void novell_group_buddy(PurpleConnection * gc, const char *name, const char *old_group_name, const char *new_group_name) { NMFolder *old_folder; NMFolder *new_folder; NMContact *contact; NMUser *user; const char *dn; NMERR_T rc = NM_OK; if (gc == NULL || name == NULL || old_group_name == NULL || new_group_name == NULL) return; user = (NMUser *) gc->proto_data; if (user && (dn = nm_lookup_dn(user, name))) { /* Find the old folder */ if (strcmp(old_group_name, NM_ROOT_FOLDER_NAME) == 0) { old_folder = nm_get_root_folder(user); if (nm_folder_find_contact(old_folder, dn) == NULL) old_folder = nm_find_folder(user, old_group_name); } else { old_folder = nm_find_folder(user, old_group_name); } if (old_folder && (contact = nm_folder_find_contact(old_folder, dn))) { /* Find the new folder */ new_folder = nm_find_folder(user, new_group_name); if (new_folder == NULL) { if (strcmp(new_group_name, NM_ROOT_FOLDER_NAME) == 0) new_folder = nm_get_root_folder(user); } if (new_folder) { /* Tell the server to move the contact to the new folder */ rc = nm_send_move_contact(user, contact, new_folder, _move_contact_resp_cb, NULL); } else { nm_contact_add_ref(contact); /* Remove the old contact first */ nm_send_remove_contact(user, old_folder, contact, _remove_contact_resp_cb, NULL); /* New folder does not exist yet, so create it */ rc = nm_send_create_folder(user, new_group_name, _create_folder_resp_move_contact, contact); } _check_for_disconnect(user, rc); } } } static void novell_rename_group(PurpleConnection * gc, const char *old_name, PurpleGroup *group, GList *moved_buddies) { NMERR_T rc = NM_OK; NMFolder *folder; NMUser *user; if (gc == NULL || old_name == NULL || group == NULL || moved_buddies == NULL) { return; } user = gc->proto_data; if (user) { /* Does new folder exist already? */ if (nm_find_folder(user, group->name)) { /* purple_blist_rename_group() adds the buddies * to the new group and removes the old group... * so there is nothing more to do here. */ return; } if (strcmp(old_name, NM_ROOT_FOLDER_NAME) == 0) { /* Can't rename the root folder ... need to revisit this */ return; } folder = nm_find_folder(user, old_name); if (folder) { rc = nm_send_rename_folder(user, folder, group->name, _rename_folder_resp_cb, NULL); _check_for_disconnect(user, rc); } } } static const char * novell_list_icon(PurpleAccount * account, PurpleBuddy * buddy) { return "novell"; } static void novell_tooltip_text(PurpleBuddy * buddy, PurpleNotifyUserInfo * user_info, gboolean full) { NMUserRecord *user_record = NULL; PurpleConnection *gc; NMUser *user; int status = 0; const char *status_str = NULL; const char *text = NULL; if (buddy == NULL) return; gc = purple_account_get_connection(buddy->account); if (gc == NULL || (user = gc->proto_data) == NULL) return; if (PURPLE_BUDDY_IS_ONLINE(buddy)) { user_record = nm_find_user_record(user, buddy->name); if (user_record) { status = nm_user_record_get_status(user_record); text = nm_user_record_get_status_text(user_record); /* No custom text, so default it ... */ switch (status) { case NM_STATUS_AVAILABLE: status_str = _("Available"); break; case NM_STATUS_AWAY: status_str = _("Away"); break; case NM_STATUS_BUSY: status_str = _("Busy"); break; case NM_STATUS_AWAY_IDLE: status_str = _("Idle"); break; case NM_STATUS_OFFLINE: status_str = _("Offline"); break; default: status_str = _("Unknown"); break; } purple_notify_user_info_add_pair(user_info, _("Status"), status_str); if (text) purple_notify_user_info_add_pair(user_info, _("Message"), text); } } } static void novell_set_idle(PurpleConnection * gc, int time) { NMUser *user; NMERR_T rc = NM_OK; const char *id = NULL; PurpleStatus *status = NULL; if (gc == NULL) return; user = gc->proto_data; if (user == NULL) return; status = purple_account_get_active_status(purple_connection_get_account(gc)); id = purple_status_get_id(status); /* Only go idle if active status is available */ if (!strcmp(id, NOVELL_STATUS_TYPE_AVAILABLE)) { if (time > 0) { rc = nm_send_set_status(user, NM_STATUS_AWAY_IDLE, NULL, NULL, NULL, NULL); } else { rc = nm_send_set_status(user, NM_STATUS_AVAILABLE, NULL, NULL, NULL, NULL); } } _check_for_disconnect(user, rc); } static void novell_get_info(PurpleConnection * gc, const char *name) { NMUserRecord *user_record; NMUser *user; NMERR_T rc; if (gc == NULL || name == NULL) return; user = (NMUser *) gc->proto_data; if (user) { user_record = nm_find_user_record(user, name); if (user_record) { _show_info(gc, user_record); } else { rc = nm_send_get_details(user, name, _get_details_resp_show_info, g_strdup(name)); _check_for_disconnect(user, rc); } } } static char * novell_status_text(PurpleBuddy * buddy) { const char *text = NULL; const char *dn = NULL; if (buddy && buddy->account) { PurpleConnection *gc = purple_account_get_connection(buddy->account); if (gc && gc->proto_data) { NMUser *user = gc->proto_data; dn = nm_lookup_dn(user, buddy->name); if (dn) { NMUserRecord *user_record = nm_find_user_record(user, dn); if (user_record) { text = nm_user_record_get_status_text(user_record); if (text) return g_strdup(text); } } } } return NULL; } static GList * novell_status_types(PurpleAccount *account) { GList *status_types = NULL; PurpleStatusType *type; g_return_val_if_fail(account != NULL, NULL); type = purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE, NOVELL_STATUS_TYPE_AVAILABLE, NULL, TRUE, TRUE, FALSE, "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), NULL); status_types = g_list_append(status_types, type); type = purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY, NOVELL_STATUS_TYPE_AWAY, NULL, TRUE, TRUE, FALSE, "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), NULL); status_types = g_list_append(status_types, type); type = purple_status_type_new_with_attrs(PURPLE_STATUS_UNAVAILABLE, NOVELL_STATUS_TYPE_BUSY, _("Busy"), TRUE, TRUE, FALSE, "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), NULL); status_types = g_list_append(status_types, type); type = purple_status_type_new_full(PURPLE_STATUS_INVISIBLE, NOVELL_STATUS_TYPE_APPEAR_OFFLINE, NULL, TRUE, TRUE, FALSE); status_types = g_list_append(status_types, type); type = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, NULL, NULL, FALSE, TRUE, FALSE); status_types = g_list_append(status_types, type); return status_types; } static void novell_set_status(PurpleAccount *account, PurpleStatus *status) { PurpleConnection *gc; gboolean connected; PurplePresence *presence; PurpleStatusType *type; PurpleStatusPrimitive primitive; NMUser *user; NMSTATUS_T novellstatus = NM_STATUS_AVAILABLE; NMERR_T rc = NM_OK; const char *msg = NULL; char *text = NULL; connected = purple_account_is_connected(account); presence = purple_status_get_presence(status); type = purple_status_get_type(status); primitive = purple_status_type_get_primitive(type); /* * We don't have any independent statuses, so we don't need to * do anything when a status is deactivated (because another * status is about to be activated). */ if (!purple_status_is_active(status)) return; if (!connected) return; gc = purple_account_get_connection(account); user = gc->proto_data; if (user == NULL) return; if (primitive == PURPLE_STATUS_AVAILABLE) { novellstatus = NM_STATUS_AVAILABLE; } else if (primitive == PURPLE_STATUS_AWAY) { novellstatus = NM_STATUS_AWAY; } else if (primitive == PURPLE_STATUS_UNAVAILABLE) { novellstatus = NM_STATUS_BUSY; } else if (primitive == PURPLE_STATUS_INVISIBLE) { novellstatus = NM_STATUS_OFFLINE; } else if (purple_presence_is_idle(presence)) { novellstatus = NM_STATUS_AWAY_IDLE; } else { novellstatus = NM_STATUS_AVAILABLE; } if (primitive == PURPLE_STATUS_AWAY || primitive == PURPLE_STATUS_AVAILABLE || primitive == PURPLE_STATUS_UNAVAILABLE) { msg = purple_status_get_attr_string(status, "message"); text = g_strdup(msg); if (primitive == PURPLE_STATUS_AVAILABLE) msg = NULL; /* no auto replies for online status */ /* Don't want newlines in status text */ purple_util_chrreplace(text, '\n', ' '); } rc = nm_send_set_status(user, novellstatus, text, msg, NULL, NULL); _check_for_disconnect(user, rc); if (text) g_free(text); } static void novell_add_permit(PurpleConnection *gc, const char *who) { NMUser *user; NMERR_T rc = NM_OK; const char *name = who; if (gc == NULL || who == NULL) return; user = gc->proto_data; if (user == NULL) return; /* Remove first -- we will add it back in when we get * the okay from the server */ purple_privacy_permit_remove(gc->account, who, TRUE); if (nm_user_is_privacy_locked(user)) { _show_privacy_locked_error(gc, user); _sync_privacy_lists(user); return; } /* Work around for problem with un-typed, dotted contexts */ if (strchr(who, '.')) { const char *dn = nm_lookup_dn(user, who); if (dn == NULL) { rc = nm_send_get_details(user, who, _get_details_send_privacy_create, (gpointer)TRUE); _check_for_disconnect(user, rc); return; } else { name = dn; } } rc = nm_send_create_privacy_item(user, name, TRUE, _create_privacy_item_permit_resp_cb, g_strdup(who)); _check_for_disconnect(user, rc); } static void novell_add_deny(PurpleConnection *gc, const char *who) { NMUser *user; NMERR_T rc = NM_OK; const char *name = who; if (gc == NULL || who == NULL) return; user = gc->proto_data; if (user == NULL) return; /* Remove first -- we will add it back in when we get * the okay from the server */ purple_privacy_deny_remove(gc->account, who, TRUE); if (nm_user_is_privacy_locked(user)) { _show_privacy_locked_error(gc, user); _sync_privacy_lists(user); return; } /* Work around for problem with un-typed, dotted contexts */ if (strchr(who, '.')) { const char *dn = nm_lookup_dn(user, who); if (dn == NULL) { rc = nm_send_get_details(user, who, _get_details_send_privacy_create, (gpointer)FALSE); _check_for_disconnect(user, rc); return; } else { name = dn; } } rc = nm_send_create_privacy_item(user, name, FALSE, _create_privacy_item_deny_resp_cb, g_strdup(who)); _check_for_disconnect(user, rc); } static void novell_rem_permit(PurpleConnection *gc, const char *who) { NMUser *user; NMERR_T rc = NM_OK; const char *dn = NULL; if (gc == NULL || who == NULL) return; user = gc->proto_data; if (user == NULL) return; if (nm_user_is_privacy_locked(user)) { _show_privacy_locked_error(gc, user); _sync_privacy_lists(user); return; } dn = nm_lookup_dn(user, who); if (dn == NULL) dn = who; rc = nm_send_remove_privacy_item(user, dn, TRUE, _remove_privacy_item_resp_cb, g_strdup(who)); _check_for_disconnect(user, rc); } static void novell_rem_deny(PurpleConnection *gc, const char *who) { NMUser *user; NMERR_T rc = NM_OK; const char *dn = NULL; if (gc == NULL || who == NULL) return; user = gc->proto_data; if (user == NULL) return; if (nm_user_is_privacy_locked(user)) { _show_privacy_locked_error(gc, user); _sync_privacy_lists(user); return; } dn = nm_lookup_dn(user, who); if (dn == NULL) dn = who; rc = nm_send_remove_privacy_item(user, dn, FALSE, _remove_privacy_item_resp_cb, g_strdup(who)); _check_for_disconnect(user, rc); } static void novell_set_permit_deny(PurpleConnection *gc) { NMERR_T rc = NM_OK; const char *dn, *name = NULL; NMUserRecord *user_record = NULL; GSList *node = NULL, *copy = NULL; NMUser *user; int i, j, num_contacts, num_folders; NMContact *contact; NMFolder *folder = NULL; if (gc == NULL) return; user = gc->proto_data; if (user == NULL) return; if (user->privacy_synched == FALSE) { _sync_privacy_lists(user); user->privacy_synched = TRUE; return; } if (nm_user_is_privacy_locked(user)) { _show_privacy_locked_error(gc, user); _sync_privacy_lists(user); return; } switch (gc->account->perm_deny) { case PURPLE_PRIVACY_ALLOW_ALL: rc = nm_send_set_privacy_default(user, FALSE, _set_privacy_default_resp_cb, NULL); _check_for_disconnect(user, rc); /* clear server side deny list */ if (rc == NM_OK) { copy = g_slist_copy(user->deny_list); for (node = copy; node && node->data; node = node->next) { rc = nm_send_remove_privacy_item(user, (const char *)node->data, FALSE, NULL, NULL); if (_check_for_disconnect(user, rc)) break; } g_slist_free(copy); g_slist_free(user->deny_list); user->deny_list = NULL; } break; case PURPLE_PRIVACY_DENY_ALL: rc = nm_send_set_privacy_default(user, TRUE, _set_privacy_default_resp_cb, NULL); _check_for_disconnect(user, rc); /* clear server side allow list */ if (rc == NM_OK) { copy = g_slist_copy(user->allow_list); for (node = copy; node && node->data; node = node->next) { rc = nm_send_remove_privacy_item(user, (const char *)node->data, TRUE, NULL, NULL); if (_check_for_disconnect(user, rc)) break; } g_slist_free(copy); g_slist_free(user->allow_list); user->allow_list = NULL; } break; case PURPLE_PRIVACY_ALLOW_USERS: rc = nm_send_set_privacy_default(user, TRUE, _set_privacy_default_resp_cb, NULL); _check_for_disconnect(user, rc); /* sync allow lists */ if (rc == NM_OK) { for (node = user->allow_list; node; node = node->next) { user_record = nm_find_user_record(user, (char *)node->data); if (user_record) { name = nm_user_record_get_display_id(user_record); if (!g_slist_find_custom(gc->account->permit, name, (GCompareFunc)purple_utf8_strcasecmp)) { purple_privacy_permit_add(gc->account, name , TRUE); } } } for (node = gc->account->permit; node; node = node->next) { name = NULL; dn = nm_lookup_dn(user, (char *)node->data); if (dn) { user_record = nm_find_user_record(user, dn); name = nm_user_record_get_display_id(user_record); if (!g_slist_find_custom(user->allow_list, dn, (GCompareFunc)purple_utf8_strcasecmp)) { rc = nm_send_create_privacy_item(user, dn, TRUE, _create_privacy_item_deny_resp_cb, g_strdup(dn)); } } else { purple_privacy_permit_remove(gc->account, (char *)node->data, TRUE); } } } break; case PURPLE_PRIVACY_DENY_USERS: /* set to default allow */ rc = nm_send_set_privacy_default(user, FALSE, _set_privacy_default_resp_cb, NULL); _check_for_disconnect(user, rc); /* sync deny lists */ if (rc == NM_OK) { for (node = user->deny_list; node; node = node->next) { user_record = nm_find_user_record(user, (char *)node->data); if (user_record) { name = nm_user_record_get_display_id(user_record); if (!g_slist_find_custom(gc->account->deny, name, (GCompareFunc)purple_utf8_strcasecmp)) { purple_privacy_deny_add(gc->account, name , TRUE); } } } for (node = gc->account->deny; node; node = node->next) { name = NULL; dn = nm_lookup_dn(user, (char *)node->data); if (dn) { user_record = nm_find_user_record(user, dn); name = nm_user_record_get_display_id(user_record); if (!g_slist_find_custom(user->deny_list, dn, (GCompareFunc)purple_utf8_strcasecmp)) { rc = nm_send_create_privacy_item(user, dn, FALSE, _create_privacy_item_deny_resp_cb, g_strdup(name)); } } else { purple_privacy_deny_remove(gc->account, (char *)node->data, TRUE); } } } break; case PURPLE_PRIVACY_ALLOW_BUDDYLIST: /* remove users from allow list that are not in buddy list */ copy = g_slist_copy(user->allow_list); for (node = copy; node && node->data; node = node->next) { if (!nm_find_contacts(user, node->data)) { rc = nm_send_remove_privacy_item(user, (const char *)node->data, TRUE, NULL, NULL); if (_check_for_disconnect(user, rc)) return; } } g_slist_free(copy); /* add all buddies to allow list */ num_contacts = nm_folder_get_contact_count(user->root_folder); for (i = 0; i < num_contacts; i++) { contact = nm_folder_get_contact(user->root_folder, i); dn = nm_contact_get_dn(contact); if (dn && !g_slist_find_custom(user->allow_list, dn, (GCompareFunc)purple_utf8_strcasecmp)) { rc = nm_send_create_privacy_item(user, dn, TRUE, _create_privacy_item_deny_resp_cb, g_strdup(dn)); if (_check_for_disconnect(user, rc)) return; } } num_folders = nm_folder_get_subfolder_count(user->root_folder); for (i = 0; i < num_folders; i++) { folder = nm_folder_get_subfolder(user->root_folder, i); num_contacts = nm_folder_get_contact_count(folder); for (j = 0; j < num_contacts; j++) { contact = nm_folder_get_contact(folder, j); dn = nm_contact_get_dn(contact); if (dn && !g_slist_find_custom(user->allow_list, dn, (GCompareFunc)purple_utf8_strcasecmp)) { rc = nm_send_create_privacy_item(user, dn, TRUE, _create_privacy_item_deny_resp_cb, g_strdup(dn)); if (_check_for_disconnect(user, rc)) return; } } } /* set to default deny */ rc = nm_send_set_privacy_default(user, TRUE, _set_privacy_default_resp_cb, NULL); if (_check_for_disconnect(user, rc)) break; break; } } static GList * novell_blist_node_menu(PurpleBlistNode *node) { GList *list = NULL; PurpleMenuAction *act; if(PURPLE_BLIST_NODE_IS_BUDDY(node)) { act = purple_menu_action_new(_("Initiate _Chat"), PURPLE_CALLBACK(_initiate_conference_cb), NULL, NULL); list = g_list_append(list, act); } return list; } static void novell_keepalive(PurpleConnection *gc) { NMUser *user; NMERR_T rc = NM_OK; if (gc == NULL) return; user = gc->proto_data; if (user == NULL) return; rc = nm_send_keepalive(user, NULL, NULL); _check_for_disconnect(user, rc); } static PurplePluginProtocolInfo prpl_info = { 0, NULL, /* user_splits */ NULL, /* protocol_options */ NO_BUDDY_ICONS, /* icon_spec */ novell_list_icon, /* list_icon */ NULL, /* list_emblems */ novell_status_text, /* status_text */ novell_tooltip_text, /* tooltip_text */ novell_status_types, /* status_types */ novell_blist_node_menu, /* blist_node_menu */ NULL, /* chat_info */ NULL, /* chat_info_defaults */ novell_login, /* login */ novell_close, /* close */ novell_send_im, /* send_im */ NULL, /* set_info */ novell_send_typing, /* send_typing */ novell_get_info, /* get_info */ novell_set_status, /* set_status */ novell_set_idle, /* set_idle */ NULL, /* change_passwd */ novell_add_buddy, /* add_buddy */ NULL, /* add_buddies */ novell_remove_buddy, /* remove_buddy */ NULL, /* remove_buddies */ novell_add_permit, /* add_permit */ novell_add_deny, /* add_deny */ novell_rem_permit, /* rem_permit */ novell_rem_deny, /* rem_deny */ novell_set_permit_deny, /* set_permit_deny */ NULL, /* join_chat */ NULL, /* reject_chat */ NULL, /* get_chat_name */ novell_chat_invite, /* chat_invite */ novell_chat_leave, /* chat_leave */ NULL, /* chat_whisper */ novell_chat_send, /* chat_send */ novell_keepalive, /* keepalive */ NULL, /* register_user */ NULL, /* get_cb_info */ NULL, /* get_cb_away */ novell_alias_buddy, /* alias_buddy */ novell_group_buddy, /* group_buddy */ novell_rename_group, /* rename_group */ NULL, /* buddy_free */ novell_convo_closed, /* convo_closed */ purple_normalize_nocase, /* normalize */ NULL, /* set_buddy_icon */ novell_remove_group, /* remove_group */ NULL, /* get_cb_real_name */ NULL, /* set_chat_topic */ NULL, /* find_blist_chat */ NULL, /* roomlist_get_list */ NULL, /* roomlist_cancel */ NULL, /* roomlist_expand_category */ NULL, /* can_receive_file */ NULL, /* send_file */ NULL, /* new_xfer */ NULL, /* offline_message */ NULL, /* whiteboard_prpl_ops */ NULL, /* send_raw */ NULL, /* roomlist_room_serialize */ /* padding */ NULL, NULL, NULL, NULL }; static PurplePluginInfo info = { PURPLE_PLUGIN_MAGIC, PURPLE_MAJOR_VERSION, PURPLE_MINOR_VERSION, PURPLE_PLUGIN_PROTOCOL, /**< type */ NULL, /**< ui_requirement */ 0, /**< flags */ NULL, /**< dependencies */ PURPLE_PRIORITY_DEFAULT, /**< priority */ "prpl-novell", /**< id */ "GroupWise", /**< name */ VERSION, /**< version */ /** summary */ N_("Novell GroupWise Messenger Protocol Plugin"), /** description */ N_("Novell GroupWise Messenger Protocol Plugin"), NULL, /**< author */ PURPLE_WEBSITE, /**< homepage */ NULL, /**< load */ NULL, /**< unload */ NULL, /**< destroy */ NULL, /**< ui_info */ &prpl_info, /**< extra_info */ NULL, NULL, /* padding */ NULL, NULL, NULL, NULL }; static void init_plugin(PurplePlugin * plugin) { PurpleAccountOption *option; option = purple_account_option_string_new(_("Server address"), "server", NULL); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); option = purple_account_option_int_new(_("Server port"), "port", DEFAULT_PORT); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option); my_protocol = plugin; } PURPLE_INIT_PLUGIN(novell, init_plugin, info);