Mercurial > pidgin.yaz
diff libpurple/protocols/jabber/jabber.c @ 19694:1d2002a5735e
propagate from branch 'im.pidgin.pidgin' (head 996cf0c57149ba6e1c714ebb1f11d5d4bac8fb68)
to branch 'im.pidgin.soc.2007.xmpp' (head cdf63b6603891b8cd3e7f629ef5a9a927a153550)
author | Andreas Monitzer <pidgin@monitzer.com> |
---|---|
date | Wed, 05 Sep 2007 22:32:14 +0000 |
parents | d470d42d2cb1 b0733d5d7621 |
children | 481749fc0b6b |
line wrap: on
line diff
--- a/libpurple/protocols/jabber/jabber.c Wed Sep 05 12:56:35 2007 +0000 +++ b/libpurple/protocols/jabber/jabber.c Wed Sep 05 22:32:14 2007 +0000 @@ -10,12 +10,12 @@ * * 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 + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "internal.h" @@ -51,19 +51,27 @@ #include "presence.h" #include "jabber.h" #include "roster.h" +#include "ping.h" #include "si.h" #include "xdata.h" +#include "pep.h" +#include "adhoccommands.h" -#define JABBER_CONNECT_STEPS (js->gsc ? 8 : 5) +#include <assert.h> + +#define JABBER_CONNECT_STEPS (js->gsc ? 9 : 5) static PurplePlugin *my_protocol = NULL; +GList *jabber_features; + +static void jabber_unregister_account_cb(JabberStream *js); static void jabber_stream_init(JabberStream *js) { char *open_stream; open_stream = g_strdup_printf("<stream:stream to='%s' " - "xmlns='jabber:client' " + "xmlns='jabber:client' " "xmlns:stream='http://etherx.jabber.org/streams' " "version='1.0'>", js->user->domain); @@ -80,6 +88,8 @@ const char *type = xmlnode_get_attrib(packet, "type"); if(type && !strcmp(type, "result")) { jabber_stream_set_state(js, JABBER_STREAM_CONNECTED); + if(js->unregistration) + jabber_unregister_account_cb(js); } else { purple_connection_error(js->gc, _("Error initializing session")); } @@ -132,6 +142,9 @@ if(xmlnode_get_child(packet, "starttls")) { if(jabber_process_starttls(js, packet)) return; + } else if(purple_account_get_bool(js->gc->account, "require_tls", FALSE) && !js->gsc) { + purple_connection_error(js->gc, _("You require encryption, but it is not available on this server.")); + return; } if(js->registration) { @@ -169,49 +182,49 @@ static void tls_init(JabberStream *js); -void jabber_process_packet(JabberStream *js, xmlnode *packet) +void jabber_process_packet(JabberStream *js, xmlnode **packet) { const char *xmlns; - purple_signal_emit(my_protocol, "jabber-receiving-xmlnode", js->gc, &packet); + purple_signal_emit(my_protocol, "jabber-receiving-xmlnode", js->gc, packet); /* if the signal leaves us with a null packet, we're done */ - if(NULL == packet) + if(NULL == *packet) return; - xmlns = xmlnode_get_namespace(packet); + xmlns = xmlnode_get_namespace(*packet); - if(!strcmp(packet->name, "iq")) { - jabber_iq_parse(js, packet); - } else if(!strcmp(packet->name, "presence")) { - jabber_presence_parse(js, packet); - } else if(!strcmp(packet->name, "message")) { - jabber_message_parse(js, packet); - } else if(!strcmp(packet->name, "stream:features")) { - jabber_stream_features_parse(js, packet); - } else if (!strcmp(packet->name, "features") && + if(!strcmp((*packet)->name, "iq")) { + jabber_iq_parse(js, *packet); + } else if(!strcmp((*packet)->name, "presence")) { + jabber_presence_parse(js, *packet); + } else if(!strcmp((*packet)->name, "message")) { + jabber_message_parse(js, *packet); + } else if(!strcmp((*packet)->name, "stream:features")) { + jabber_stream_features_parse(js, *packet); + } else if (!strcmp((*packet)->name, "features") && !strcmp(xmlns, "http://etherx.jabber.org/streams")) { - jabber_stream_features_parse(js, packet); - } else if(!strcmp(packet->name, "stream:error") || - (!strcmp(packet->name, "error") && + jabber_stream_features_parse(js, *packet); + } else if(!strcmp((*packet)->name, "stream:error") || + (!strcmp((*packet)->name, "error") && !strcmp(xmlns, "http://etherx.jabber.org/streams"))) { - jabber_stream_handle_error(js, packet); - } else if(!strcmp(packet->name, "challenge")) { + jabber_stream_handle_error(js, *packet); + } else if(!strcmp((*packet)->name, "challenge")) { if(js->state == JABBER_STREAM_AUTHENTICATING) - jabber_auth_handle_challenge(js, packet); - } else if(!strcmp(packet->name, "success")) { + jabber_auth_handle_challenge(js, *packet); + } else if(!strcmp((*packet)->name, "success")) { if(js->state == JABBER_STREAM_AUTHENTICATING) - jabber_auth_handle_success(js, packet); - } else if(!strcmp(packet->name, "failure")) { + jabber_auth_handle_success(js, *packet); + } else if(!strcmp((*packet)->name, "failure")) { if(js->state == JABBER_STREAM_AUTHENTICATING) - jabber_auth_handle_failure(js, packet); - } else if(!strcmp(packet->name, "proceed")) { + jabber_auth_handle_failure(js, *packet); + } else if(!strcmp((*packet)->name, "proceed")) { if(js->state == JABBER_STREAM_AUTHENTICATING && !js->gsc) tls_init(js); } else { purple_debug(PURPLE_DEBUG_WARNING, "jabber", "Unknown packet: %s\n", - packet->name); + (*packet)->name); } } @@ -448,11 +461,14 @@ } js = gc->proto_data; - + if(js->state == JABBER_STREAM_CONNECTING) jabber_send_raw(js, "<?xml version='1.0' ?>", -1); jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING); purple_ssl_input_add(gsc, jabber_recv_cb_ssl, gc); + + /* Tell the app that we're doing encryption */ + jabber_stream_set_state(js, JABBER_STREAM_INITIALIZING_ENCRYPTION); } @@ -554,6 +570,7 @@ js->user = jabber_id_new(purple_account_get_username(account)); js->next_id = g_random_int(); js->write_buffer = purple_circ_buffer_new(512); + js->old_length = -1; if(!js->user) { purple_connection_error(gc, _("Invalid XMPP ID")); @@ -613,6 +630,8 @@ { JabberStream *js = data; PurpleAccount *account = purple_connection_get_account(js->gc); + + jabber_parser_free(js); purple_account_disconnect(account); @@ -628,12 +647,21 @@ static void jabber_registration_result_cb(JabberStream *js, xmlnode *packet, gpointer data) { + PurpleAccount *account = purple_connection_get_account(js->gc); const char *type = xmlnode_get_attrib(packet, "type"); char *buf; + char *to = data; if(!strcmp(type, "result")) { - buf = g_strdup_printf(_("Registration of %s@%s successful"), + if(js->registration) { + buf = g_strdup_printf(_("Registration of %s@%s successful"), js->user->node, js->user->domain); + if(account->registration_cb) + (account->registration_cb)(account, TRUE, account->registration_cb_user_data); + } + else + buf = g_strdup_printf(_("Registration to %s successful"), + to); purple_notify_info(NULL, _("Registration Successful"), _("Registration Successful"), buf); g_free(buf); @@ -646,20 +674,56 @@ purple_notify_error(NULL, _("Registration Failed"), _("Registration Failed"), msg); g_free(msg); + if(account->registration_cb) + (account->registration_cb)(account, FALSE, account->registration_cb_user_data); } - jabber_connection_schedule_close(js); + g_free(to); + if(js->registration) + jabber_connection_schedule_close(js); } static void -jabber_register_cb(JabberStream *js, PurpleRequestFields *fields) +jabber_unregistration_result_cb(JabberStream *js, xmlnode *packet, gpointer data) +{ + const char *type = xmlnode_get_attrib(packet, "type"); + char *buf; + char *to = data; + + if(!strcmp(type, "result")) { + buf = g_strdup_printf(_("Registration from %s successfully removed"), + to); + purple_notify_info(NULL, _("Unregistration Successful"), + _("Unregistration Successful"), buf); + g_free(buf); + } else { + char *msg = jabber_parse_error(js, packet); + + if(!msg) + msg = g_strdup(_("Unknown Error")); + + purple_notify_error(NULL, _("Unregistration Failed"), + _("Unregistration Failed"), msg); + g_free(msg); + } + g_free(to); +} + +typedef struct _JabberRegisterCBData { + JabberStream *js; + char *who; +} JabberRegisterCBData; + +static void +jabber_register_cb(JabberRegisterCBData *cbdata, PurpleRequestFields *fields) { GList *groups, *flds; xmlnode *query, *y; JabberIq *iq; char *username; - iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:register"); + iq = jabber_iq_new_query(cbdata->js, JABBER_IQ_SET, "jabber:iq:register"); query = xmlnode_get_child(iq->node, "query"); + xmlnode_set_attrib(iq->node,"to",cbdata->who); for(groups = purple_request_fields_get_groups(fields); groups; groups = groups->next) { @@ -667,215 +731,297 @@ flds; flds = flds->next) { PurpleRequestField *field = flds->data; const char *id = purple_request_field_get_id(field); - const char *value = purple_request_field_string_get_value(field); - - if(!strcmp(id, "username")) { - y = xmlnode_new_child(query, "username"); - } else if(!strcmp(id, "password")) { - y = xmlnode_new_child(query, "password"); - } else if(!strcmp(id, "name")) { - y = xmlnode_new_child(query, "name"); - } else if(!strcmp(id, "email")) { - y = xmlnode_new_child(query, "email"); - } else if(!strcmp(id, "nick")) { - y = xmlnode_new_child(query, "nick"); - } else if(!strcmp(id, "first")) { - y = xmlnode_new_child(query, "first"); - } else if(!strcmp(id, "last")) { - y = xmlnode_new_child(query, "last"); - } else if(!strcmp(id, "address")) { - y = xmlnode_new_child(query, "address"); - } else if(!strcmp(id, "city")) { - y = xmlnode_new_child(query, "city"); - } else if(!strcmp(id, "state")) { - y = xmlnode_new_child(query, "state"); - } else if(!strcmp(id, "zip")) { - y = xmlnode_new_child(query, "zip"); - } else if(!strcmp(id, "phone")) { - y = xmlnode_new_child(query, "phone"); - } else if(!strcmp(id, "url")) { - y = xmlnode_new_child(query, "url"); - } else if(!strcmp(id, "date")) { - y = xmlnode_new_child(query, "date"); + if(!strcmp(id,"unregister")) { + gboolean value = purple_request_field_bool_get_value(field); + if(value) { + /* unregister from service. this doesn't include any of the fields, so remove them from the stanza by recreating it + (there's no "remove child" function for xmlnode) */ + jabber_iq_free(iq); + iq = jabber_iq_new_query(cbdata->js, JABBER_IQ_SET, "jabber:iq:register"); + query = xmlnode_get_child(iq->node, "query"); + xmlnode_set_attrib(iq->node,"to",cbdata->who); + xmlnode_new_child(query, "remove"); + + jabber_iq_set_callback(iq, jabber_unregistration_result_cb, cbdata->who); + + jabber_iq_send(iq); + g_free(cbdata); + return; + } } else { - continue; - } - xmlnode_insert_data(y, value, -1); - if(!strcmp(id, "username")) { - if(js->user->node) - g_free(js->user->node); - js->user->node = g_strdup(value); + const char *value = purple_request_field_string_get_value(field); + + if(!strcmp(id, "username")) { + y = xmlnode_new_child(query, "username"); + } else if(!strcmp(id, "password")) { + y = xmlnode_new_child(query, "password"); + } else if(!strcmp(id, "name")) { + y = xmlnode_new_child(query, "name"); + } else if(!strcmp(id, "email")) { + y = xmlnode_new_child(query, "email"); + } else if(!strcmp(id, "nick")) { + y = xmlnode_new_child(query, "nick"); + } else if(!strcmp(id, "first")) { + y = xmlnode_new_child(query, "first"); + } else if(!strcmp(id, "last")) { + y = xmlnode_new_child(query, "last"); + } else if(!strcmp(id, "address")) { + y = xmlnode_new_child(query, "address"); + } else if(!strcmp(id, "city")) { + y = xmlnode_new_child(query, "city"); + } else if(!strcmp(id, "state")) { + y = xmlnode_new_child(query, "state"); + } else if(!strcmp(id, "zip")) { + y = xmlnode_new_child(query, "zip"); + } else if(!strcmp(id, "phone")) { + y = xmlnode_new_child(query, "phone"); + } else if(!strcmp(id, "url")) { + y = xmlnode_new_child(query, "url"); + } else if(!strcmp(id, "date")) { + y = xmlnode_new_child(query, "date"); + } else { + continue; + } + xmlnode_insert_data(y, value, -1); + if(cbdata->js->registration && !strcmp(id, "username")) { + if(cbdata->js->user->node) + g_free(cbdata->js->user->node); + cbdata->js->user->node = g_strdup(value); + } + if(cbdata->js->registration && !strcmp(id, "password")) + purple_account_set_password(cbdata->js->gc->account, value); } } } - username = g_strdup_printf("%s@%s/%s", js->user->node, js->user->domain, - js->user->resource); - purple_account_set_username(js->gc->account, username); - g_free(username); + if(cbdata->js->registration) { + username = g_strdup_printf("%s@%s/%s", cbdata->js->user->node, cbdata->js->user->domain, + cbdata->js->user->resource); + purple_account_set_username(cbdata->js->gc->account, username); + g_free(username); + } - jabber_iq_set_callback(iq, jabber_registration_result_cb, NULL); + jabber_iq_set_callback(iq, jabber_registration_result_cb, cbdata->who); jabber_iq_send(iq); - + g_free(cbdata); } static void -jabber_register_cancel_cb(JabberStream *js, PurpleRequestFields *fields) +jabber_register_cancel_cb(JabberRegisterCBData *cbdata, PurpleRequestFields *fields) { - jabber_connection_schedule_close(js); + PurpleAccount *account = purple_connection_get_account(cbdata->js->gc); + if(account && cbdata->js->registration) { + if(account->registration_cb) + (account->registration_cb)(account, FALSE, account->registration_cb_user_data); + jabber_connection_schedule_close(cbdata->js); + } + g_free(cbdata->who); + g_free(cbdata); } static void jabber_register_x_data_cb(JabberStream *js, xmlnode *result, gpointer data) { xmlnode *query; JabberIq *iq; + char *to = data; iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:register"); query = xmlnode_get_child(iq->node, "query"); + xmlnode_set_attrib(iq->node,"to",to); xmlnode_insert_child(query, result); - jabber_iq_set_callback(iq, jabber_registration_result_cb, NULL); + jabber_iq_set_callback(iq, jabber_registration_result_cb, to); jabber_iq_send(iq); } void jabber_register_parse(JabberStream *js, xmlnode *packet) { + PurpleAccount *account = purple_connection_get_account(js->gc); const char *type; + const char *from = xmlnode_get_attrib(packet, "from"); + PurpleRequestFields *fields; + PurpleRequestFieldGroup *group; + PurpleRequestField *field; + xmlnode *query, *x, *y; + char *instructions; + JabberRegisterCBData *cbdata; + gboolean registered = FALSE; + if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) return; - if(js->registration) { - PurpleRequestFields *fields; - PurpleRequestFieldGroup *group; - PurpleRequestField *field; - xmlnode *query, *x, *y; - char *instructions; - + if(js->registration) /* get rid of the login thingy */ purple_connection_set_state(js->gc, PURPLE_CONNECTED); - query = xmlnode_get_child(packet, "query"); + query = xmlnode_get_child(packet, "query"); - if(xmlnode_get_child(query, "registered")) { + if(xmlnode_get_child(query, "registered")) { + registered = TRUE; + + if(js->registration) { purple_notify_error(NULL, _("Already Registered"), _("Already Registered"), NULL); + if(account->registration_cb) + (account->registration_cb)(account, FALSE, account->registration_cb_user_data); jabber_connection_schedule_close(js); return; } + } - if((x = xmlnode_get_child_with_namespace(packet, "x", - "jabber:x:data"))) { - jabber_x_data_request(js, x, jabber_register_x_data_cb, NULL); - return; - } else if((x = xmlnode_get_child_with_namespace(packet, "x", - "jabber:x:oob"))) { - xmlnode *url; + if((x = xmlnode_get_child_with_namespace(packet, "x", + "jabber:x:data"))) { + jabber_x_data_request(js, x, jabber_register_x_data_cb, g_strdup(from)); + return; + } else if((x = xmlnode_get_child_with_namespace(packet, "x", + "jabber:x:oob"))) { + xmlnode *url; - if((url = xmlnode_get_child(x, "url"))) { - char *href; - if((href = xmlnode_get_data(url))) { - purple_notify_uri(NULL, href); - g_free(href); + if((url = xmlnode_get_child(x, "url"))) { + char *href; + if((href = xmlnode_get_data(url))) { + purple_notify_uri(NULL, href); + g_free(href); + if(js->registration) { js->gc->wants_to_die = TRUE; + if(account->registration_cb) /* succeeded, but we have no login info */ + (account->registration_cb)(account, TRUE, account->registration_cb_user_data); jabber_connection_schedule_close(js); - return; } + return; } } + } - /* as a last resort, use the old jabber:iq:register syntax */ + /* as a last resort, use the old jabber:iq:register syntax */ - fields = purple_request_fields_new(); - group = purple_request_field_group_new(NULL); - purple_request_fields_add_group(fields, group); + fields = purple_request_fields_new(); + group = purple_request_field_group_new(NULL); + purple_request_fields_add_group(fields, group); + if(js->registration) field = purple_request_field_string_new("username", _("Username"), js->user->node, FALSE); - purple_request_field_group_add_field(group, field); + else + field = purple_request_field_string_new("username", _("Username"), + NULL, FALSE); + purple_request_field_group_add_field(group, field); + + if(js->registration) field = purple_request_field_string_new("password", _("Password"), purple_connection_get_password(js->gc), FALSE); - purple_request_field_string_set_masked(field, TRUE); - purple_request_field_group_add_field(group, field); + else + field = purple_request_field_string_new("password", _("Password"), + NULL, FALSE); - if(xmlnode_get_child(query, "name")) { + purple_request_field_string_set_masked(field, TRUE); + purple_request_field_group_add_field(group, field); + + if(xmlnode_get_child(query, "name")) { + if(js->registration) field = purple_request_field_string_new("name", _("Name"), purple_account_get_alias(js->gc->account), FALSE); - purple_request_field_group_add_field(group, field); - } - if(xmlnode_get_child(query, "email")) { - field = purple_request_field_string_new("email", _("E-mail"), - NULL, FALSE); - purple_request_field_group_add_field(group, field); - } - if(xmlnode_get_child(query, "nick")) { - field = purple_request_field_string_new("nick", _("Nickname"), - NULL, FALSE); - purple_request_field_group_add_field(group, field); - } - if(xmlnode_get_child(query, "first")) { - field = purple_request_field_string_new("first", _("First name"), - NULL, FALSE); - purple_request_field_group_add_field(group, field); - } - if(xmlnode_get_child(query, "last")) { - field = purple_request_field_string_new("last", _("Last name"), - NULL, FALSE); - purple_request_field_group_add_field(group, field); - } - if(xmlnode_get_child(query, "address")) { - field = purple_request_field_string_new("address", _("Address"), - NULL, FALSE); - purple_request_field_group_add_field(group, field); - } - if(xmlnode_get_child(query, "city")) { - field = purple_request_field_string_new("city", _("City"), + else + field = purple_request_field_string_new("name", _("Name"), NULL, FALSE); - purple_request_field_group_add_field(group, field); - } - if(xmlnode_get_child(query, "state")) { - field = purple_request_field_string_new("state", _("State"), - NULL, FALSE); - purple_request_field_group_add_field(group, field); - } - if(xmlnode_get_child(query, "zip")) { - field = purple_request_field_string_new("zip", _("Postal code"), - NULL, FALSE); - purple_request_field_group_add_field(group, field); - } - if(xmlnode_get_child(query, "phone")) { - field = purple_request_field_string_new("phone", _("Phone"), - NULL, FALSE); - purple_request_field_group_add_field(group, field); - } - if(xmlnode_get_child(query, "url")) { - field = purple_request_field_string_new("url", _("URL"), - NULL, FALSE); - purple_request_field_group_add_field(group, field); - } - if(xmlnode_get_child(query, "date")) { - field = purple_request_field_string_new("date", _("Date"), - NULL, FALSE); - purple_request_field_group_add_field(group, field); - } + purple_request_field_group_add_field(group, field); + } + if(xmlnode_get_child(query, "email")) { + field = purple_request_field_string_new("email", _("E-mail"), + NULL, FALSE); + purple_request_field_group_add_field(group, field); + } + if(xmlnode_get_child(query, "nick")) { + field = purple_request_field_string_new("nick", _("Nickname"), + NULL, FALSE); + purple_request_field_group_add_field(group, field); + } + if(xmlnode_get_child(query, "first")) { + field = purple_request_field_string_new("first", _("First name"), + NULL, FALSE); + purple_request_field_group_add_field(group, field); + } + if(xmlnode_get_child(query, "last")) { + field = purple_request_field_string_new("last", _("Last name"), + NULL, FALSE); + purple_request_field_group_add_field(group, field); + } + if(xmlnode_get_child(query, "address")) { + field = purple_request_field_string_new("address", _("Address"), + NULL, FALSE); + purple_request_field_group_add_field(group, field); + } + if(xmlnode_get_child(query, "city")) { + field = purple_request_field_string_new("city", _("City"), + NULL, FALSE); + purple_request_field_group_add_field(group, field); + } + if(xmlnode_get_child(query, "state")) { + field = purple_request_field_string_new("state", _("State"), + NULL, FALSE); + purple_request_field_group_add_field(group, field); + } + if(xmlnode_get_child(query, "zip")) { + field = purple_request_field_string_new("zip", _("Postal code"), + NULL, FALSE); + purple_request_field_group_add_field(group, field); + } + if(xmlnode_get_child(query, "phone")) { + field = purple_request_field_string_new("phone", _("Phone"), + NULL, FALSE); + purple_request_field_group_add_field(group, field); + } + if(xmlnode_get_child(query, "url")) { + field = purple_request_field_string_new("url", _("URL"), + NULL, FALSE); + purple_request_field_group_add_field(group, field); + } + if(xmlnode_get_child(query, "date")) { + field = purple_request_field_string_new("date", _("Date"), + NULL, FALSE); + purple_request_field_group_add_field(group, field); + } + if(registered) { + field = purple_request_field_bool_new("unregister", _("Unregister"), FALSE); + purple_request_field_group_add_field(group, field); + } - if((y = xmlnode_get_child(query, "instructions"))) - instructions = xmlnode_get_data(y); - else - instructions = g_strdup(_("Please fill out the information below " - "to register your new account.")); + if((y = xmlnode_get_child(query, "instructions"))) + instructions = xmlnode_get_data(y); + else if(registered) + instructions = g_strdup(_("Please fill out the information below " + "to change your account registration.")); + else + instructions = g_strdup(_("Please fill out the information below " + "to register your new account.")); + + cbdata = g_new0(JabberRegisterCBData, 1); + cbdata->js = js; + cbdata->who = g_strdup(from); + if(js->registration) purple_request_fields(js->gc, _("Register New XMPP Account"), _("Register New XMPP Account"), instructions, fields, _("Register"), G_CALLBACK(jabber_register_cb), _("Cancel"), G_CALLBACK(jabber_register_cancel_cb), purple_connection_get_account(js->gc), NULL, NULL, - js); + cbdata); + else { + char *title = registered?g_strdup_printf(_("Change Account Registration at %s"), from) + :g_strdup_printf(_("Register New Account at %s"), from); + purple_request_fields(js->gc, title, + title, instructions, fields, + registered?_("Change Registration"):_("Register"), G_CALLBACK(jabber_register_cb), + _("Cancel"), G_CALLBACK(jabber_register_cancel_cb), + purple_connection_get_account(js->gc), NULL, NULL, + cbdata); + g_free(title); + } - g_free(instructions); - } + g_free(instructions); } void jabber_register_start(JabberStream *js) @@ -886,6 +1032,14 @@ jabber_iq_send(iq); } +void jabber_register_gateway(JabberStream *js, const char *gateway) { + JabberIq *iq; + + iq = jabber_iq_new_query(js, JABBER_IQ_GET, "jabber:iq:register"); + xmlnode_set_attrib(iq->node, "to", gateway); + jabber_iq_send(iq); +} + void jabber_register_account(PurpleAccount *account) { PurpleConnection *gc = purple_account_get_connection(account); @@ -904,6 +1058,7 @@ g_free, g_free); js->user = jabber_id_new(purple_account_get_username(account)); js->next_id = g_random_int(); + js->old_length = -1; if(!js->user) { purple_connection_error(gc, _("Invalid XMPP ID")); @@ -945,18 +1100,77 @@ if(!js->gsc) { if (connect_server[0]) { jabber_login_connect(js, js->user->domain, server, - purple_account_get_int(account, - "port", 5222)); + purple_account_get_int(account, + "port", 5222)); } else { js->srv_query_data = purple_srv_resolve("xmpp-client", - "tcp", - js->user->domain, - srv_resolved_cb, - js); + "tcp", + js->user->domain, + srv_resolved_cb, + js); } } } +static void jabber_unregister_account_iq_cb(JabberStream *js, xmlnode *packet, gpointer data) { + PurpleAccount *account = purple_connection_get_account(js->gc); + const char *type = xmlnode_get_attrib(packet,"type"); + if(!strcmp(type,"error")) { + char *msg = jabber_parse_error(js, packet); + + purple_notify_error(js->gc, _("Error unregistering account"), + _("Error unregistering account"), msg); + g_free(msg); + if(js->unregistration_cb) + js->unregistration_cb(account, FALSE, js->unregistration_user_data); + } else if(!strcmp(type,"result")) { + purple_notify_info(js->gc, _("Account successfully unregistered"), + _("Account successfully unregistered"), NULL); + if(js->unregistration_cb) + js->unregistration_cb(account, TRUE, js->unregistration_user_data); + } +} + +static void jabber_unregister_account_cb(JabberStream *js) { + JabberIq *iq; + xmlnode *query; + assert(js->unregistration); + + iq = jabber_iq_new_query(js,JABBER_IQ_SET,"jabber:iq:register"); + assert(iq); + query = xmlnode_get_child_with_namespace(iq->node,"query","jabber:iq:register"); + assert(query); + xmlnode_new_child(query,"remove"); + + xmlnode_set_attrib(iq->node,"to",js->user->domain); + jabber_iq_set_callback(iq,jabber_unregister_account_iq_cb,NULL); + + jabber_iq_send(iq); +} + +void jabber_unregister_account(PurpleAccount *account, PurpleAccountUnregistrationCb cb, void *user_data) { + PurpleConnection *gc = purple_account_get_connection(account); + JabberStream *js; + + if(gc->state != PURPLE_CONNECTED) { + if(gc->state != PURPLE_CONNECTING) + jabber_login(account); + js = gc->proto_data; + js->unregistration = TRUE; + js->unregistration_cb = cb; + js->unregistration_user_data = user_data; + return; + } + + js = gc->proto_data; + assert(!js->unregistration); /* don't allow multiple calls */ + js->unregistration = TRUE; + js->unregistration_cb = cb; + js->unregistration_user_data = user_data; + + jabber_unregister_account_cb(js); +} + void jabber_close(PurpleConnection *gc) { JabberStream *js = gc->proto_data; @@ -984,6 +1198,8 @@ jabber_buddy_remove_all_pending_buddy_info_requests(js); + jabber_parser_free(js); + if(js->iq_callbacks) g_hash_table_destroy(js->iq_callbacks); if(js->disco_callbacks) @@ -1019,9 +1235,32 @@ #endif if(js->serverFQDN) g_free(js->serverFQDN); + while(js->commands) { + JabberAdHocCommands *cmd = js->commands->data; + g_free(cmd->jid); + g_free(cmd->node); + g_free(cmd->name); + g_free(cmd); + js->commands = g_list_delete_link(js->commands, js->commands); + } g_free(js->server_name); g_free(js->gmail_last_time); g_free(js->gmail_last_tid); + if(js->old_msg) + g_free(js->old_msg); + if(js->old_avatarhash) + g_free(js->old_avatarhash); + if(js->old_artist) + g_free(js->old_artist); + if(js->old_title) + g_free(js->old_title); + if(js->old_source) + g_free(js->old_source); + if(js->old_uri) + g_free(js->old_uri); + if(js->old_track) + g_free(js->old_track); + g_free(js); gc->proto_data = NULL; @@ -1042,9 +1281,13 @@ js->gsc ? 5 : 2, JABBER_CONNECT_STEPS); jabber_stream_init(js); break; + case JABBER_STREAM_INITIALIZING_ENCRYPTION: + purple_connection_update_progress(js->gc, _("Initializing SSL/TLS"), + 6, JABBER_CONNECT_STEPS); + break; case JABBER_STREAM_AUTHENTICATING: purple_connection_update_progress(js->gc, _("Authenticating"), - js->gsc ? 6 : 3, JABBER_CONNECT_STEPS); + js->gsc ? 7 : 3, JABBER_CONNECT_STEPS); if(js->protocol_version == JABBER_PROTO_0_9 && js->registration) { jabber_register_start(js); } else if(js->auth_type == JABBER_AUTH_IQ_AUTH) { @@ -1053,7 +1296,7 @@ break; case JABBER_STREAM_REINITIALIZING: purple_connection_update_progress(js->gc, _("Re-initializing Stream"), - (js->gsc ? 7 : 4), JABBER_CONNECT_STEPS); + (js->gsc ? 8 : 4), JABBER_CONNECT_STEPS); /* The stream will be reinitialized later, in jabber_recv_cb_ssl() */ js->reinit = TRUE; @@ -1080,6 +1323,38 @@ js->idle = idle ? time(NULL) - idle : idle; } +void jabber_add_feature(const char *shortname, const char *namespace, JabberFeatureEnabled cb) { + JabberFeature *feat; + + assert(shortname != NULL); + assert(namespace != NULL); + + feat = g_new0(JabberFeature,1); + feat->shortname = g_strdup(shortname); + feat->namespace = g_strdup(namespace); + feat->is_enabled = cb; + + /* try to remove just in case it already exists in the list */ + jabber_remove_feature(shortname); + + jabber_features = g_list_append(jabber_features, feat); +} + +void jabber_remove_feature(const char *shortname) { + GList *feature; + for(feature = jabber_features; feature; feature = feature->next) { + JabberFeature *feat = (JabberFeature*)feature->data; + if(!strcmp(feat->shortname, shortname)) { + g_free(feat->shortname); + g_free(feat->namespace); + + g_free(feature->data); + feature = g_list_delete_link(feature, feature); + break; + } + } +} + const char *jabber_list_icon(PurpleAccount *a, PurpleBuddy *b) { return "jabber"; @@ -1154,6 +1429,9 @@ GList *l; if (full) { + PurpleStatus *status; + PurpleValue *value; + if(jb->subscription & JABBER_SUB_FROM) { if(jb->subscription & JABBER_SUB_TO) sub = _("Both"); @@ -1171,6 +1449,21 @@ } purple_notify_user_info_add_pair(user_info, _("Subscription"), sub); + + status = purple_presence_get_active_status(purple_buddy_get_presence(b)); + value = purple_status_get_attr_value(status, "mood"); + if(value && purple_value_get_type(value) == PURPLE_TYPE_STRING) { + const char *mood = purple_value_get_string(value); + + value = purple_status_get_attr_value(status, "moodtext"); + if(value && purple_value_get_type(value) == PURPLE_TYPE_STRING) { + char *moodplustext = g_strdup_printf("%s (%s)",mood,purple_value_get_string(value)); + + purple_notify_user_info_add_pair(user_info, _("Mood"), moodplustext); + g_free(moodplustext); + } else + purple_notify_user_info_add_pair(user_info, _("Mood"), mood); + } } for(l=jb->resources; l; l = l->next) { @@ -1233,6 +1526,19 @@ NULL, TRUE, TRUE, FALSE, "priority", _("Priority"), priority_value, "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), + "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), + "tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), + "tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), + "tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), + "tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), + "tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), + "tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), + "tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), + "tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), + "tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), + "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), + "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); types = g_list_append(types, type); @@ -1243,6 +1549,19 @@ _("Chatty"), TRUE, TRUE, FALSE, "priority", _("Priority"), priority_value, "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), + "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), + "tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), + "tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), + "tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), + "tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), + "tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), + "tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), + "tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), + "tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), + "tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), + "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), + "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); types = g_list_append(types, type); @@ -1253,6 +1572,19 @@ NULL, TRUE, TRUE, FALSE, "priority", _("Priority"), priority_value, "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), + "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), + "tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), + "tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), + "tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), + "tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), + "tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), + "tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), + "tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), + "tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), + "tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), + "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), + "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); types = g_list_append(types, type); @@ -1263,6 +1595,19 @@ NULL, TRUE, TRUE, FALSE, "priority", _("Priority"), priority_value, "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), + "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), + "tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), + "tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), + "tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), + "tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), + "tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), + "tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), + "tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), + "tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), + "tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), + "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), + "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); types = g_list_append(types, type); @@ -1273,6 +1618,19 @@ _("Do Not Disturb"), TRUE, TRUE, FALSE, "priority", _("Priority"), priority_value, "message", _("Message"), purple_value_new(PURPLE_TYPE_STRING), + "mood", _("Mood"), purple_value_new(PURPLE_TYPE_STRING), + "moodtext", _("Mood Text"), purple_value_new(PURPLE_TYPE_STRING), + "tune_artist", _("Tune Artist"), purple_value_new(PURPLE_TYPE_STRING), + "tune_title", _("Tune Title"), purple_value_new(PURPLE_TYPE_STRING), + "tune_album", _("Tune Album"), purple_value_new(PURPLE_TYPE_STRING), + "tune_genre", _("Tune Genre"), purple_value_new(PURPLE_TYPE_STRING), + "tune_comment", _("Tune Comment"), purple_value_new(PURPLE_TYPE_STRING), + "tune_track", _("Tune Track"), purple_value_new(PURPLE_TYPE_STRING), + "tune_time", _("Tune Time"), purple_value_new(PURPLE_TYPE_INT), + "tune_year", _("Tune Year"), purple_value_new(PURPLE_TYPE_INT), + "tune_url", _("Tune URL"), purple_value_new(PURPLE_TYPE_STRING), + "nick", _("Nickname"), purple_value_new(PURPLE_TYPE_STRING), + "buzz", _("Allow Buzz"), purple_value_new(PURPLE_TYPE_BOOLEAN), NULL); types = g_list_append(types, type); @@ -1379,23 +1737,33 @@ GList *jabber_actions(PurplePlugin *plugin, gpointer context) { + PurpleConnection *gc = (PurpleConnection *) context; + JabberStream *js = gc->proto_data; GList *m = NULL; PurplePluginAction *act; act = purple_plugin_action_new(_("Set User Info..."), - jabber_setup_set_info); + jabber_setup_set_info); m = g_list_append(m, act); /* if (js->protocol_options & CHANGE_PASSWORD) { */ act = purple_plugin_action_new(_("Change Password..."), - jabber_password_change); + jabber_password_change); m = g_list_append(m, act); /* } */ act = purple_plugin_action_new(_("Search for Users..."), - jabber_user_search_begin); + jabber_user_search_begin); m = g_list_append(m, act); + purple_debug_info("jabber", "jabber_actions: have pep: %s\n", js->pep?"YES":"NO"); + + if(js->pep) + jabber_pep_init_actions(&m); + + if(js->commands) + jabber_adhoc_init_server_commands(js, &m); + return m; } @@ -1690,10 +2058,10 @@ return PURPLE_CMD_RET_FAILED; if (strcmp(args[1], "owner") != 0 && - strcmp(args[1], "admin") != 0 && - strcmp(args[1], "member") != 0 && - strcmp(args[1], "outcast") != 0 && - strcmp(args[1], "none") != 0) { + strcmp(args[1], "admin") != 0 && + strcmp(args[1], "member") != 0 && + strcmp(args[1], "outcast") != 0 && + strcmp(args[1], "none") != 0) { *error = g_strdup_printf(_("Unknown affiliation: \"%s\""), args[1]); return PURPLE_CMD_RET_FAILED; } @@ -1715,16 +2083,16 @@ return PURPLE_CMD_RET_FAILED; if (strcmp(args[1], "moderator") != 0 && - strcmp(args[1], "participant") != 0 && - strcmp(args[1], "visitor") != 0 && - strcmp(args[1], "none") != 0) { + strcmp(args[1], "participant") != 0 && + strcmp(args[1], "visitor") != 0 && + strcmp(args[1], "none") != 0) { *error = g_strdup_printf(_("Unknown role: \"%s\""), args[1]); return PURPLE_CMD_RET_FAILED; } if (!jabber_chat_role_user(chat, args[0], args[1])) { *error = g_strdup_printf(_("Unable to set role \"%s\" for user: %s"), - args[1], args[0]); + args[1], args[0]); return PURPLE_CMD_RET_FAILED; } @@ -1800,6 +2168,71 @@ return PURPLE_CMD_RET_OK; } +static PurpleCmdRet jabber_cmd_ping(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + if(!args || !args[0]) + return PURPLE_CMD_RET_FAILED; + + if(!jabber_ping_jid(conv, args[0])) { + *error = g_strdup_printf(_("Unable to ping user %s"), args[0]); + return PURPLE_CMD_RET_FAILED; + } + + return PURPLE_CMD_RET_OK; +} + +static PurpleCmdRet jabber_cmd_buzz(PurpleConversation *conv, + const char *cmd, char **args, char **error, void *data) +{ + JabberStream *js = conv->account->gc->proto_data; + xmlnode *msg, *buzz; + JabberBuddy *jb; + JabberBuddyResource *jbr; + char *to; + GList *iter; + + if(!args || !args[0]) + return PURPLE_CMD_RET_FAILED; + + jb = jabber_buddy_find(js, args[0], FALSE); + if(!jb) { + *error = g_strdup_printf(_("Unable to buzz, because there is nothing known about user %s."), args[0]); + return PURPLE_CMD_RET_FAILED; + } + + jbr = jabber_buddy_find_resource(jb, NULL); + if(!jbr) { + *error = g_strdup_printf(_("Unable to buzz, because user %s might be offline."), args[0]); + return PURPLE_CMD_RET_FAILED; + } + if(!jbr->caps) { + *error = g_strdup_printf(_("Unable to buzz, because there is nothing known about user %s."), args[0]); + return PURPLE_CMD_RET_FAILED; + } + for(iter = jbr->caps->features; iter; iter = g_list_next(iter)) { + if(!strcmp(iter->data, "http://www.xmpp.org/extensions/xep-0224.html#ns")) { + msg = xmlnode_new("message"); + to = g_strdup_printf("%s/%s", args[0], jbr->name); + xmlnode_set_attrib(msg,"to",to); + g_free(to); + + /* avoid offline storage */ + xmlnode_set_attrib(msg,"type","headline"); + + buzz = xmlnode_new_child(msg,"attention"); + xmlnode_set_namespace(buzz,"http://www.xmpp.org/extensions/xep-0224.html#ns"); + + jabber_send(js,msg); + xmlnode_free(msg); + + return PURPLE_CMD_RET_OK; + } + } + *error = g_strdup_printf(_("Unable to buzz, because the user %s does not support it."), args[0]); + return PURPLE_CMD_RET_FAILED; +} + gboolean jabber_offline_message(const PurpleBuddy *buddy) { return TRUE; @@ -1808,79 +2241,89 @@ void jabber_register_commands(void) { purple_cmd_register("config", "", PURPLE_CMD_P_PRPL, - PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, - "prpl-jabber", jabber_cmd_chat_config, - _("config: Configure a chat room."), NULL); + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-jabber", jabber_cmd_chat_config, + _("config: Configure a chat room."), NULL); purple_cmd_register("configure", "", PURPLE_CMD_P_PRPL, - PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, - "prpl-jabber", jabber_cmd_chat_config, - _("configure: Configure a chat room."), NULL); + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-jabber", jabber_cmd_chat_config, + _("configure: Configure a chat room."), NULL); purple_cmd_register("nick", "s", PURPLE_CMD_P_PRPL, - PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, - "prpl-jabber", jabber_cmd_chat_nick, - _("nick <new nickname>: Change your nickname."), - NULL); + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-jabber", jabber_cmd_chat_nick, + _("nick <new nickname>: Change your nickname."), + NULL); purple_cmd_register("part", "s", PURPLE_CMD_P_PRPL, - PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | - PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", - jabber_cmd_chat_part, _("part [room]: Leave the room."), - NULL); + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", + jabber_cmd_chat_part, _("part [room]: Leave the room."), + NULL); purple_cmd_register("register", "", PURPLE_CMD_P_PRPL, - PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, - "prpl-jabber", jabber_cmd_chat_register, - _("register: Register with a chat room."), NULL); + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-jabber", jabber_cmd_chat_register, + _("register: Register with a chat room."), NULL); /* XXX: there needs to be a core /topic cmd, methinks */ purple_cmd_register("topic", "s", PURPLE_CMD_P_PRPL, - PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | - PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", - jabber_cmd_chat_topic, - _("topic [new topic]: View or change the topic."), - NULL); + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", + jabber_cmd_chat_topic, + _("topic [new topic]: View or change the topic."), + NULL); purple_cmd_register("ban", "ws", PURPLE_CMD_P_PRPL, - PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | - PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", - jabber_cmd_chat_ban, - _("ban <user> [room]: Ban a user from the room."), - NULL); + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", + jabber_cmd_chat_ban, + _("ban <user> [room]: Ban a user from the room."), + NULL); purple_cmd_register("affiliate", "ws", PURPLE_CMD_P_PRPL, - PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | - PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", - jabber_cmd_chat_affiliate, - _("affiliate <user> <owner|admin|member|outcast|none>: Set a user's affiliation with the room."), - NULL); + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", + jabber_cmd_chat_affiliate, + _("affiliate <user> <owner|admin|member|outcast|none>: Set a user's affiliation with the room."), + NULL); purple_cmd_register("role", "ws", PURPLE_CMD_P_PRPL, - PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | - PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", - jabber_cmd_chat_role, - _("role <user> <moderator|participant|visitor|none>: Set a user's role in the room."), - NULL); + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", + jabber_cmd_chat_role, + _("role <user> <moderator|participant|visitor|none>: Set a user's role in the room."), + NULL); purple_cmd_register("invite", "ws", PURPLE_CMD_P_PRPL, - PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | - PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", - jabber_cmd_chat_invite, - _("invite <user> [message]: Invite a user to the room."), - NULL); + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", + jabber_cmd_chat_invite, + _("invite <user> [message]: Invite a user to the room."), + NULL); purple_cmd_register("join", "ws", PURPLE_CMD_P_PRPL, - PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | - PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", - jabber_cmd_chat_join, - _("join: <room> [server]: Join a chat on this server."), - NULL); + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", + jabber_cmd_chat_join, + _("join: <room> [server]: Join a chat on this server."), + NULL); purple_cmd_register("kick", "ws", PURPLE_CMD_P_PRPL, - PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | - PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", - jabber_cmd_chat_kick, - _("kick <user> [room]: Kick a user from the room."), - NULL); + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY | + PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, "prpl-jabber", + jabber_cmd_chat_kick, + _("kick <user> [room]: Kick a user from the room."), + NULL); purple_cmd_register("msg", "ws", PURPLE_CMD_P_PRPL, - PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, - "prpl-jabber", jabber_cmd_chat_msg, - _("msg <user> <message>: Send a private message to another user."), - NULL); + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-jabber", jabber_cmd_chat_msg, + _("msg <user> <message>: Send a private message to another user."), + NULL); + purple_cmd_register("ping", "w", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM | + PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-jabber", jabber_cmd_ping, + _("ping <jid>: Ping a user/component/server."), + NULL); + purple_cmd_register("buzz", "s", PURPLE_CMD_P_PRPL, + PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_PRPL_ONLY, + "prpl-jabber", jabber_cmd_buzz, + _("buzz: Buzz a user to get their attention"), NULL); } void jabber_init_plugin(PurplePlugin *plugin) { - my_protocol = plugin; + my_protocol = plugin; }