diff options
author | Sebastien Helleu <flashcode@flashtux.org> | 2009-01-15 15:29:05 +0100 |
---|---|---|
committer | Sebastien Helleu <flashcode@flashtux.org> | 2009-01-15 15:29:05 +0100 |
commit | 18a62f1dac870c96152063d69336ecfaf563da69 (patch) | |
tree | 7989acb4aebf8749f7ddb5e48e13431f93e0ce33 /src/plugins | |
parent | c717d206cd73c0445a9edd1a5b723ea79a107676 (diff) | |
download | weechat-18a62f1dac870c96152063d69336ecfaf563da69.zip |
Add Jabber plugin (alpha version, many Jabber features are missing)
This commit introduces Jabber/XMPP protocol for WeeChat. It uses iksemel lib.
Please note many major Jabber features are missing:
- roster management (add/remove/.. buddies),
- MUC,
- transports.
It is possible to define servers (with /jabber), connect to them (with
/jconnect), disconnect (/jdisconnect) and chat with buddies (with /jchat).
Diffstat (limited to 'src/plugins')
60 files changed, 9272 insertions, 276 deletions
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index a4408a79a..0b4eae29f 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -58,6 +58,14 @@ IF(NOT DISABLE_IRC) ADD_SUBDIRECTORY( irc ) ENDIF(NOT DISABLE_IRC) +IF(NOT DISABLE_JABBER) + # Check for iksemel library + FIND_PACKAGE(Iksemel) + IF(IKSEMEL_FOUND) + ADD_SUBDIRECTORY( jabber ) + ENDIF(IKSEMEL_FOUND) +ENDIF(NOT DISABLE_JABBER) + IF(NOT DISABLE_LOGGER) ADD_SUBDIRECTORY( logger ) ENDIF(NOT DISABLE_LOGGER) diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index 31c529992..a716f2cd2 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -50,6 +50,10 @@ if PLUGIN_IRC irc_dir = irc endif +if PLUGIN_JABBER +jabber_dir = jabber +endif + if PLUGIN_LOGGER logger_dir = logger endif @@ -91,5 +95,5 @@ xfer_dir = xfer endif SUBDIRS = . $(alias_dir) $(aspell_dir) $(charset_dir) $(demo_dir) $(fifo_dir) \ - $(irc_dir) $(logger_dir) $(notify_dir) $(relay_dir) $(script_dir) \ - $(trigger_dir) $(xfer_dir) + $(irc_dir) $(jabber_dir) $(logger_dir) $(notify_dir) $(relay_dir) \ + $(script_dir) $(trigger_dir) $(xfer_dir) diff --git a/src/plugins/fifo/fifo.c b/src/plugins/fifo/fifo.c index fe16f2015..3484af9eb 100644 --- a/src/plugins/fifo/fifo.c +++ b/src/plugins/fifo/fifo.c @@ -96,7 +96,7 @@ fifo_create () O_RDONLY | O_NONBLOCK)) != -1) { weechat_printf (NULL, - _("%s: pipe open"), + _("%s: pipe opened"), FIFO_PLUGIN_NAME), rc = 1; } diff --git a/src/plugins/irc/irc-buffer.c b/src/plugins/irc/irc-buffer.c index 86640f603..7792a8845 100644 --- a/src/plugins/irc/irc-buffer.c +++ b/src/plugins/irc/irc-buffer.c @@ -16,7 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* irc-buffer.c: manages buffers for IRC plugin */ +/* irc-buffer.c: buffer functions for IRC plugin */ #include <stdlib.h> diff --git a/src/plugins/irc/irc-channel.c b/src/plugins/irc/irc-channel.c index daf9adced..c3fab2cd1 100644 --- a/src/plugins/irc/irc-channel.c +++ b/src/plugins/irc/irc-channel.c @@ -61,7 +61,7 @@ irc_channel_valid (struct t_irc_server *server, struct t_irc_channel *channel) } /* - * irc_channel_new: allocate a new channel for a server and add it to servers + * irc_channel_new: allocate a new channel for a server and add it to channels * list */ @@ -142,19 +142,19 @@ irc_channel_new (struct t_irc_server *server, int channel_type, new_channel->modes = NULL; new_channel->limit = 0; new_channel->key = NULL; - new_channel->nicks_count = 0; new_channel->checking_away = 0; new_channel->away_message = NULL; new_channel->cycle = 0; new_channel->display_creation_date = 0; new_channel->nick_completion_reset = 0; + new_channel->nicks_count = 0; new_channel->nicks = NULL; new_channel->last_nick = NULL; - new_channel->buffer = new_buffer; new_channel->nicks_speaking[0] = NULL; new_channel->nicks_speaking[1] = NULL; new_channel->nicks_speaking_time = NULL; new_channel->last_nick_speaking_time = NULL; + new_channel->buffer = new_buffer; new_channel->buffer_as_string = NULL; /* add new channel to channels list */ @@ -270,14 +270,14 @@ irc_channel_check_away (struct t_irc_server *server, */ void -irc_channel_set_away (struct t_irc_channel *channel, const char *nick, +irc_channel_set_away (struct t_irc_channel *channel, const char *nick_name, int is_away) { struct t_irc_nick *ptr_nick; if (channel->type == IRC_CHANNEL_TYPE_CHANNEL) { - ptr_nick = irc_nick_search (channel, nick); + ptr_nick = irc_nick_search (channel, nick_name); if (ptr_nick) irc_nick_set_away (channel, ptr_nick, is_away); } @@ -288,8 +288,8 @@ irc_channel_set_away (struct t_irc_channel *channel, const char *nick, */ void -irc_channel_nick_speaking_add (struct t_irc_channel *channel, const char *nick, - int highlight) +irc_channel_nick_speaking_add (struct t_irc_channel *channel, + const char *nick_name, int highlight) { int size, to_remove, i; @@ -301,7 +301,7 @@ irc_channel_nick_speaking_add (struct t_irc_channel *channel, const char *nick, if (!channel->nicks_speaking[highlight]) channel->nicks_speaking[highlight] = weechat_list_new (); - weechat_list_add (channel->nicks_speaking[highlight], nick, + weechat_list_add (channel->nicks_speaking[highlight], nick_name, WEECHAT_LIST_POS_END); size = weechat_list_size (channel->nicks_speaking[highlight]); @@ -346,7 +346,7 @@ irc_channel_nick_speaking_rename (struct t_irc_channel *channel, struct t_irc_channel_speaking * irc_channel_nick_speaking_time_search (struct t_irc_channel *channel, - const char *nick, + const char *nick_name, int check_time) { struct t_irc_channel_speaking *ptr_nick; @@ -358,7 +358,7 @@ irc_channel_nick_speaking_time_search (struct t_irc_channel *channel, for (ptr_nick = channel->nicks_speaking_time; ptr_nick; ptr_nick = ptr_nick->next_nick) { - if (strcmp (ptr_nick->nick, nick) == 0) + if (strcmp (ptr_nick->nick, nick_name) == 0) { if (check_time && (ptr_nick->time_last_message < time_limit)) return NULL; @@ -376,23 +376,23 @@ irc_channel_nick_speaking_time_search (struct t_irc_channel *channel, void irc_channel_nick_speaking_time_free (struct t_irc_channel *channel, - struct t_irc_channel_speaking *nick) + struct t_irc_channel_speaking *nick_speaking) { /* free data */ - if (nick->nick) - free (nick->nick); + if (nick_speaking->nick) + free (nick_speaking->nick); /* remove nick from list */ - if (nick->prev_nick) - (nick->prev_nick)->next_nick = nick->next_nick; - if (nick->next_nick) - (nick->next_nick)->prev_nick = nick->prev_nick; - if (channel->nicks_speaking_time == nick) - channel->nicks_speaking_time = nick->next_nick; - if (channel->last_nick_speaking_time == nick) - channel->last_nick_speaking_time = nick->prev_nick; - - free (nick); + if (nick_speaking->prev_nick) + (nick_speaking->prev_nick)->next_nick = nick_speaking->next_nick; + if (nick_speaking->next_nick) + (nick_speaking->next_nick)->prev_nick = nick_speaking->prev_nick; + if (channel->nicks_speaking_time == nick_speaking) + channel->nicks_speaking_time = nick_speaking->next_nick; + if (channel->last_nick_speaking_time == nick_speaking) + channel->last_nick_speaking_time = nick_speaking->prev_nick; + + free (nick_speaking); } /* @@ -437,19 +437,19 @@ irc_channel_nick_speaking_time_remove_old (struct t_irc_channel *channel) void irc_channel_nick_speaking_time_add (struct t_irc_channel *channel, - const char *nick, + const char *nick_name, time_t time_last_message) { struct t_irc_channel_speaking *ptr_nick, *new_nick; - ptr_nick = irc_channel_nick_speaking_time_search (channel, nick, 0); + ptr_nick = irc_channel_nick_speaking_time_search (channel, nick_name, 0); if (ptr_nick) irc_channel_nick_speaking_time_free (channel, ptr_nick); new_nick = malloc (sizeof (*new_nick)); if (new_nick) { - new_nick->nick = strdup (nick); + new_nick->nick = strdup (nick_name); new_nick->time_last_message = time_last_message; /* insert nick at beginning of list */ @@ -538,15 +538,16 @@ irc_channel_free (struct t_irc_server *server, struct t_irc_channel *channel) } /* - * irc_channel_free_all: free all allocated channels + * irc_channel_free_all: free all allocated channels for a server */ void irc_channel_free_all (struct t_irc_server *server) { - /* remove all channels for the server */ while (server->channels) + { irc_channel_free (server, server->channels); + } } /* @@ -669,12 +670,16 @@ irc_channel_print_log (struct t_irc_channel *channel) weechat_log_printf (" away_message . . . . . . : '%s'", channel->away_message); weechat_log_printf (" cycle. . . . . . . . . . : %d", channel->cycle); weechat_log_printf (" display_creation_date. . : %d", channel->display_creation_date); + weechat_log_printf (" nick_completion_reset. . : %d", channel->nick_completion_reset); + weechat_log_printf (" nicks_count. . . . . . . : %d", channel->nicks_count); weechat_log_printf (" nicks. . . . . . . . . . : 0x%lx", channel->nicks); weechat_log_printf (" last_nick. . . . . . . . : 0x%lx", channel->last_nick); - weechat_log_printf (" buffer . . . . . . . . . : 0x%lx", channel->buffer); - weechat_log_printf (" nicks_speaking . . . . . : 0x%lx", channel->nicks_speaking); + weechat_log_printf (" nicks_speaking[0]. . . . : 0x%lx", channel->nicks_speaking[0]); + weechat_log_printf (" nicks_speaking[1]. . . . : 0x%lx", channel->nicks_speaking[1]); weechat_log_printf (" nicks_speaking_time. . . : 0x%lx", channel->nicks_speaking_time); weechat_log_printf (" last_nick_speaking_time. : 0x%lx", channel->last_nick_speaking_time); + weechat_log_printf (" buffer . . . . . . . . . : 0x%lx", channel->buffer); + weechat_log_printf (" buffer_as_string . . . . : '%s'", channel->buffer_as_string); weechat_log_printf (" prev_channel . . . . . . : 0x%lx", channel->prev_channel); weechat_log_printf (" next_channel . . . . . . : 0x%lx", channel->next_channel); for (i = 0; i < 2; i++) diff --git a/src/plugins/irc/irc-channel.h b/src/plugins/irc/irc-channel.h index c6c36160a..bd129f6fa 100644 --- a/src/plugins/irc/irc-channel.h +++ b/src/plugins/irc/irc-channel.h @@ -47,13 +47,13 @@ struct t_irc_channel char *modes; /* channel modes */ int limit; /* user limit (0 is limit not set) */ char *key; /* channel key (NULL if no key set) */ - int nicks_count; /* # nicks on channel (0 if pv) */ int checking_away; /* = 1 if checking away with WHO cmd */ char *away_message; /* to display away only once in pv */ int cycle; /* currently cycling (/part + /join) */ int display_creation_date; /* 1 for displaying creation date */ int nick_completion_reset; /* 1 for resetting nick completion */ /* there was some join/part on chan */ + int nicks_count; /* # nicks on channel (0 if pv) */ struct t_irc_nick *nicks; /* nicks on the channel */ struct t_irc_nick *last_nick; /* last nick on the channel */ struct t_weelist *nicks_speaking[2]; /* for smart completion: first */ @@ -85,20 +85,21 @@ extern int irc_channel_is_channel (const char *string); extern void irc_channel_remove_away (struct t_irc_channel *channel); extern void irc_channel_check_away (struct t_irc_server *server, struct t_irc_channel *channel, int force); -extern void irc_channel_set_away (struct t_irc_channel *channel, const char *nick, +extern void irc_channel_set_away (struct t_irc_channel *channel, + const char *nick_name, int is_away); extern void irc_channel_nick_speaking_add (struct t_irc_channel *channel, - const char *nick, + const char *nick_name, int highlight); extern void irc_channel_nick_speaking_rename (struct t_irc_channel *channel, const char *old_nick, const char *new_nick); extern struct t_irc_channel_speaking *irc_channel_nick_speaking_time_search (struct t_irc_channel *channel, - const char *nick, + const char *nick_name, int check_time); extern void irc_channel_nick_speaking_time_remove_old (struct t_irc_channel *channel); extern void irc_channel_nick_speaking_time_add (struct t_irc_channel *channel, - const char *nick, + const char *nick_name, time_t time_last_message); extern void irc_channel_nick_speaking_time_rename (struct t_irc_channel *channel, const char *old_nick, diff --git a/src/plugins/irc/irc-color.c b/src/plugins/irc/irc-color.c index c210c9d45..91a60ac93 100644 --- a/src/plugins/irc/irc-color.c +++ b/src/plugins/irc/irc-color.c @@ -268,12 +268,12 @@ irc_color_encode (const char *string, int keep_colors) { switch (ptr_string[0]) { - case 0x02: // ^B + case 0x02: /* ^B */ if (keep_colors) out[out_pos++] = IRC_COLOR_BOLD_CHAR; ptr_string++; break; - case 0x03: // ^C + case 0x03: /* ^C */ if (keep_colors) out[out_pos++] = IRC_COLOR_COLOR_CHAR; ptr_string++; @@ -308,17 +308,17 @@ irc_color_encode (const char *string, int keep_colors) } } break; - case 0x0F: // ^O + case 0x0F: /* ^O */ if (keep_colors) out[out_pos++] = IRC_COLOR_RESET_CHAR; ptr_string++; break; - case 0x12: // ^R + case 0x12: /* ^R */ if (keep_colors) out[out_pos++] = IRC_COLOR_REVERSE_CHAR; ptr_string++; break; - case 0x15: // ^U + case 0x15: /* ^U */ if (keep_colors) out[out_pos++] = IRC_COLOR_UNDERLINE_CHAR; ptr_string++; diff --git a/src/plugins/irc/irc-command.c b/src/plugins/irc/irc-command.c index 46585a392..ec2c974ce 100644 --- a/src/plugins/irc/irc-command.c +++ b/src/plugins/irc/irc-command.c @@ -16,7 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* irc-command.c: IRC commands managment */ +/* irc-command.c: IRC commands */ #include <stdlib.h> @@ -35,6 +35,7 @@ #include "irc-buffer.h" #include "irc-color.h" #include "irc-config.h" +#include "irc-input.h" #include "irc-server.h" #include "irc-channel.h" #include "irc-nick.h" @@ -515,7 +516,8 @@ irc_command_connect_one_server (struct t_irc_server *server, int no_join) server->name); return 0; } - if (irc_server_connect (server, no_join)) + server->disable_autojoin = no_join; + if (irc_server_connect (server)) { server->reconnect_start = 0; server->reconnect_join = (server->channels) ? 1 : 0; @@ -1132,7 +1134,7 @@ irc_command_quit_server (struct t_irc_server *server, const char *arguments) /* * irc_command_disconnect_one_server: disconnect from a server - * return 0 if error, 1 if ok + * return 0 if error, 1 if ok */ int @@ -2526,12 +2528,8 @@ irc_command_query (void *data, struct t_gui_buffer *buffer, int argc, { string = irc_color_decode (argv_eol[2], weechat_config_boolean (irc_config_network_colors_receive)); - weechat_printf (ptr_channel->buffer, - "%s%s", - irc_nick_as_prefix (NULL, - ptr_server->nick, - IRC_COLOR_CHAT_NICK_SELF), - (string) ? string : argv_eol[2]); + irc_input_user_message_display (ptr_channel->buffer, + (string) ? string : argv_eol[2]); if (string) free (string); irc_server_sendf (ptr_server, "PRIVMSG %s :%s", @@ -2593,7 +2591,8 @@ irc_command_reconnect_one_server (struct t_irc_server *server, int no_join) } irc_command_quit_server (server, NULL); irc_server_disconnect (server, 0); - if (irc_server_connect (server, no_join)) + server->disable_autojoin = no_join; + if (irc_server_connect (server)) { server->reconnect_start = 0; server->reconnect_join = (server->channels) ? 1 : 0; @@ -2870,7 +2869,7 @@ irc_command_server (void *data, struct t_gui_buffer *buffer, int argc, IRC_COLOR_CHAT); if (IRC_SERVER_OPTION_BOOLEAN(new_server, IRC_SERVER_OPTION_AUTOCONNECT)) - irc_server_connect (new_server, 0); + irc_server_connect (new_server); return WEECHAT_RC_OK; } @@ -3733,7 +3732,7 @@ irc_command_init () "nickname: user or host to ban"), "%(irc_channel_nicks_hosts)", &irc_command_ban, NULL); weechat_hook_command ("connect", - N_("connect to server(s)"), + N_("connect to IRC server(s)"), N_("[-all [-nojoin] | servername [servername ...] " "[-nojoin] | hostname [-port port] [-ipv6] " "[-ssl]]"), @@ -3794,7 +3793,7 @@ irc_command_init () "", NULL, &irc_command_die, NULL); weechat_hook_command ("disconnect", - N_("disconnect from server(s)"), + N_("disconnect from IRC server(s)"), N_("[-all | servername [servername ...]]"), N_(" -all: disconnect from all servers\n" "servername: server name to disconnect"), @@ -4028,7 +4027,7 @@ irc_command_init () " type: reserved for future usage"), NULL, &irc_command_service, NULL); weechat_hook_command ("server", - N_("list, add or remove servers"), + N_("list, add or remove IRC servers"), N_("[list [servername]] | [listfull [servername]] | " "[add servername hostname[/port] " "[-auto | -noauto] [-ipv6] [-ssl]] | " diff --git a/src/plugins/irc/irc-command.h b/src/plugins/irc/irc-command.h index 34557e260..4cc654be7 100644 --- a/src/plugins/irc/irc-command.h +++ b/src/plugins/irc/irc-command.h @@ -24,8 +24,9 @@ struct t_irc_server; #define IRC_COMMAND_TOO_FEW_ARGUMENTS(__buffer, __command) \ weechat_printf (__buffer, \ - _("%sirc: too few arguments for \"%s\" command"), \ + _("%s%s: too few arguments for \"%s\" command"), \ irc_buffer_get_server_prefix (ptr_server, "error"), \ + IRC_PLUGIN_NAME, \ __command); \ return WEECHAT_RC_ERROR; diff --git a/src/plugins/irc/irc-completion.c b/src/plugins/irc/irc-completion.c index 6e1e25f77..4052b0bec 100644 --- a/src/plugins/irc/irc-completion.c +++ b/src/plugins/irc/irc-completion.c @@ -35,7 +35,7 @@ /* - * irc_completion_server_cb: callback for completion with current IRC server + * irc_completion_server_cb: callback for completion with current server */ int @@ -60,7 +60,7 @@ irc_completion_server_cb (void *data, const char *completion_item, /* * irc_completion_server_nick_cb: callback for completion with self nick - * of current IRC server + * of current server */ int @@ -85,7 +85,7 @@ irc_completion_server_nick_cb (void *data, const char *completion_item, /* * irc_completion_server_nicks_cb: callback for completion with nicks - * of current IRC server + * of current server */ int @@ -127,7 +127,7 @@ irc_completion_server_nicks_cb (void *data, const char *completion_item, } /* - * irc_completion_servers_cb: callback for completion with IRC servers + * irc_completion_servers_cb: callback for completion with servers */ int @@ -153,7 +153,7 @@ irc_completion_servers_cb (void *data, const char *completion_item, } /* - * irc_completion_channel_cb: callback for completion with current IRC channel + * irc_completion_channel_cb: callback for completion with current channel */ int @@ -178,7 +178,7 @@ irc_completion_channel_cb (void *data, const char *completion_item, /* * irc_completion_channel_nicks_cb: callback for completion with nicks - * of current IRC channel + * of current channel */ int @@ -198,47 +198,53 @@ irc_completion_channel_nicks_cb (void *data, const char *completion_item, if (ptr_channel) { - if (ptr_channel->type == IRC_CHANNEL_TYPE_CHANNEL) + switch (ptr_channel->type) { - for (ptr_nick = ptr_channel->nicks; ptr_nick; - ptr_nick = ptr_nick->next_nick) - { - weechat_hook_completion_list_add (completion, ptr_nick->name, - 1, WEECHAT_LIST_POS_SORT); - } - - /* add nicks speaking recently on this channel */ - if (weechat_config_boolean (irc_config_look_nick_completion_smart)) - { - /* 0 => nick speaking ; 1 => nick speaking to me (with highlight) */ - for (i = 0; i < 2; i++) + case IRC_CHANNEL_TYPE_CHANNEL: + for (ptr_nick = ptr_channel->nicks; ptr_nick; + ptr_nick = ptr_nick->next_nick) + { + weechat_hook_completion_list_add (completion, + ptr_nick->name, + 1, + WEECHAT_LIST_POS_SORT); + } + /* add nicks speaking recently on this channel */ + if (weechat_config_boolean (irc_config_look_nick_completion_smart)) { - if (ptr_channel->nicks_speaking[i]) + /* 0 => nick speaking ; 1 => nick speaking to me (with highlight) */ + for (i = 0; i < 2; i++) { - list_size = weechat_list_size (ptr_channel->nicks_speaking[i]); - for (j = 0; j < list_size; j++) + if (ptr_channel->nicks_speaking[i]) { - nick = weechat_list_string (weechat_list_get (ptr_channel->nicks_speaking[i], j)); - if (nick && irc_nick_search (ptr_channel, nick)) + list_size = weechat_list_size (ptr_channel->nicks_speaking[i]); + for (j = 0; j < list_size; j++) { - weechat_hook_completion_list_add (completion, nick, - 1, WEECHAT_LIST_POS_BEGINNING); + nick = weechat_list_string (weechat_list_get (ptr_channel->nicks_speaking[i], j)); + if (nick && irc_nick_search (ptr_channel, nick)) + { + weechat_hook_completion_list_add (completion, + nick, + 1, + WEECHAT_LIST_POS_BEGINNING); + } } } } } - } - - /* add self nick at the end */ - weechat_hook_completion_list_add (completion, ptr_server->nick, - 1, WEECHAT_LIST_POS_END); - } - if (ptr_channel->type == IRC_CHANNEL_TYPE_PRIVATE) - { - weechat_hook_completion_list_add (completion, ptr_channel->name, - 0, WEECHAT_LIST_POS_SORT); + /* add self nick at the end */ + weechat_hook_completion_list_add (completion, + ptr_server->nick, + 1, + WEECHAT_LIST_POS_END); + break; + case IRC_CHANNEL_TYPE_PRIVATE: + weechat_hook_completion_list_add (completion, + ptr_channel->name, + 0, + WEECHAT_LIST_POS_SORT); + break; } - ptr_channel->nick_completion_reset = 0; } @@ -247,7 +253,7 @@ irc_completion_channel_nicks_cb (void *data, const char *completion_item, /* * irc_completion_channel_nicks_hosts_cb: callback for completion with nicks - * and hosts of current IRC channel + * and hosts of current channel */ int @@ -267,33 +273,40 @@ irc_completion_channel_nicks_hosts_cb (void *data, const char *completion_item, if (ptr_channel) { - if (ptr_channel->type == IRC_CHANNEL_TYPE_CHANNEL) + switch (ptr_channel->type) { - for (ptr_nick = ptr_channel->nicks; ptr_nick; - ptr_nick = ptr_nick->next_nick) - { - weechat_hook_completion_list_add (completion, ptr_nick->name, - 1, WEECHAT_LIST_POS_SORT); - if (ptr_nick->host) + case IRC_CHANNEL_TYPE_CHANNEL: + for (ptr_nick = ptr_channel->nicks; ptr_nick; + ptr_nick = ptr_nick->next_nick) { - length = strlen (ptr_nick->name) + 1 + - strlen (ptr_nick->host) + 1; - buf = malloc (length); - if (buf) + weechat_hook_completion_list_add (completion, + ptr_nick->name, + 1, + WEECHAT_LIST_POS_SORT); + if (ptr_nick->host) { - snprintf (buf, length, "%s!%s", - ptr_nick->name, ptr_nick->host); - weechat_hook_completion_list_add (completion, buf, - 0, WEECHAT_LIST_POS_SORT); - free (buf); + length = strlen (ptr_nick->name) + 1 + + strlen (ptr_nick->host) + 1; + buf = malloc (length); + if (buf) + { + snprintf (buf, length, "%s!%s", + ptr_nick->name, ptr_nick->host); + weechat_hook_completion_list_add (completion, + buf, + 0, + WEECHAT_LIST_POS_SORT); + free (buf); + } } } - } - } - if (ptr_channel->type == IRC_CHANNEL_TYPE_PRIVATE) - { - weechat_hook_completion_list_add (completion, ptr_channel->name, - 0, WEECHAT_LIST_POS_SORT); + break; + case IRC_CHANNEL_TYPE_PRIVATE: + weechat_hook_completion_list_add (completion, + ptr_channel->name, + 0, + WEECHAT_LIST_POS_SORT); + break; } } @@ -302,7 +315,7 @@ irc_completion_channel_nicks_hosts_cb (void *data, const char *completion_item, /* * irc_completion_channel_topic_cb: callback for completion with topic of - * current IRC channel + * current channel */ int @@ -332,7 +345,7 @@ irc_completion_channel_topic_cb (void *data, const char *completion_item, } /* - * irc_completion_channels_cb: callback for completion with IRC channels + * irc_completion_channels_cb: callback for completion with channels */ int @@ -394,19 +407,24 @@ irc_completion_msg_part_cb (void *data, const char *completion_item, void irc_completion_init () { - weechat_hook_completion ("irc_server", &irc_completion_server_cb, NULL); + weechat_hook_completion ("irc_server", + &irc_completion_server_cb, NULL); weechat_hook_completion ("irc_server_nick", &irc_completion_server_nick_cb, NULL); weechat_hook_completion ("irc_server_nicks", &irc_completion_server_nicks_cb, NULL); - weechat_hook_completion ("irc_servers", &irc_completion_servers_cb, NULL); - weechat_hook_completion ("irc_channel", &irc_completion_channel_cb, NULL); + weechat_hook_completion ("irc_servers", + &irc_completion_servers_cb, NULL); + weechat_hook_completion ("irc_channel", + &irc_completion_channel_cb, NULL); weechat_hook_completion ("nick", &irc_completion_channel_nicks_cb, NULL); weechat_hook_completion ("irc_channel_nicks_hosts", &irc_completion_channel_nicks_hosts_cb, NULL); weechat_hook_completion ("irc_channel_topic", &irc_completion_channel_topic_cb, NULL); - weechat_hook_completion ("irc_channels", &irc_completion_channels_cb, NULL); - weechat_hook_completion ("irc_msg_part", &irc_completion_msg_part_cb, NULL); + weechat_hook_completion ("irc_channels", + &irc_completion_channels_cb, NULL); + weechat_hook_completion ("irc_msg_part", + &irc_completion_msg_part_cb, NULL); } diff --git a/src/plugins/irc/irc-config.c b/src/plugins/irc/irc-config.c index 415c86076..8ced94784 100644 --- a/src/plugins/irc/irc-config.c +++ b/src/plugins/irc/irc-config.c @@ -569,11 +569,11 @@ irc_config_server_new_option (struct t_config_file *config_file, switch (index_option) { - case IRC_SERVER_OPTION_AUTOCONNECT: + case IRC_SERVER_OPTION_ADDRESSES: new_option = weechat_config_new_option ( config_file, section, - option_name, "boolean", - N_("automatically connect to server when WeeChat is starting"), + option_name, "string", + N_("list of hostname/port or IP/port for server (separated by comma)"), NULL, 0, 0, default_value, value, null_value_allowed, @@ -581,11 +581,11 @@ irc_config_server_new_option (struct t_config_file *config_file, callback_change, callback_change_data, NULL, NULL); break; - case IRC_SERVER_OPTION_AUTORECONNECT: + case IRC_SERVER_OPTION_PROXY: new_option = weechat_config_new_option ( config_file, section, - option_name, "boolean", - N_("automatically reconnect to server when disconnected"), + option_name, "string", + N_("proxy used for this server (optional)"), NULL, 0, 0, default_value, value, null_value_allowed, @@ -593,23 +593,23 @@ irc_config_server_new_option (struct t_config_file *config_file, callback_change, callback_change_data, NULL, NULL); break; - case IRC_SERVER_OPTION_AUTORECONNECT_DELAY: + case IRC_SERVER_OPTION_IPV6: new_option = weechat_config_new_option ( config_file, section, - option_name, "integer", - N_("delay (in seconds) before trying again to reconnect to server"), - NULL, 0, 65535, + option_name, "boolean", + N_("use IPv6 protocol for server communication"), + NULL, 0, 0, default_value, value, null_value_allowed, NULL, NULL, callback_change, callback_change_data, NULL, NULL); break; - case IRC_SERVER_OPTION_PROXY: + case IRC_SERVER_OPTION_SSL: new_option = weechat_config_new_option ( config_file, section, - option_name, "string", - N_("proxy used for this server (optional)"), + option_name, "boolean", + N_("use SSL for server communication"), NULL, 0, 0, default_value, value, null_value_allowed, @@ -617,11 +617,11 @@ irc_config_server_new_option (struct t_config_file *config_file, callback_change, callback_change_data, NULL, NULL); break; - case IRC_SERVER_OPTION_ADDRESSES: + case IRC_SERVER_OPTION_PASSWORD: new_option = weechat_config_new_option ( config_file, section, option_name, "string", - N_("list of IP/port or hostname/port for server (separated by comma)"), + N_("password for server"), NULL, 0, 0, default_value, value, null_value_allowed, @@ -629,11 +629,11 @@ irc_config_server_new_option (struct t_config_file *config_file, callback_change, callback_change_data, NULL, NULL); break; - case IRC_SERVER_OPTION_IPV6: + case IRC_SERVER_OPTION_AUTOCONNECT: new_option = weechat_config_new_option ( config_file, section, option_name, "boolean", - N_("use IPv6 protocol for server communication"), + N_("automatically connect to server when WeeChat is starting"), NULL, 0, 0, default_value, value, null_value_allowed, @@ -641,11 +641,11 @@ irc_config_server_new_option (struct t_config_file *config_file, callback_change, callback_change_data, NULL, NULL); break; - case IRC_SERVER_OPTION_SSL: + case IRC_SERVER_OPTION_AUTORECONNECT: new_option = weechat_config_new_option ( config_file, section, option_name, "boolean", - N_("use SSL for server communication"), + N_("automatically reconnect to server when disconnected"), NULL, 0, 0, default_value, value, null_value_allowed, @@ -653,12 +653,12 @@ irc_config_server_new_option (struct t_config_file *config_file, callback_change, callback_change_data, NULL, NULL); break; - case IRC_SERVER_OPTION_PASSWORD: + case IRC_SERVER_OPTION_AUTORECONNECT_DELAY: new_option = weechat_config_new_option ( config_file, section, - option_name, "string", - N_("password for IRC server"), - NULL, 0, 0, + option_name, "integer", + N_("delay (in seconds) before trying again to reconnect to server"), + NULL, 0, 65535, default_value, value, null_value_allowed, NULL, NULL, @@ -669,7 +669,7 @@ irc_config_server_new_option (struct t_config_file *config_file, new_option = weechat_config_new_option ( config_file, section, option_name, "string", - N_("nicknames to use on IRC server (separated by comma)"), + N_("nicknames to use on server (separated by comma)"), NULL, 0, 0, default_value, value, null_value_allowed, @@ -681,7 +681,7 @@ irc_config_server_new_option (struct t_config_file *config_file, new_option = weechat_config_new_option ( config_file, section, option_name, "string", - N_("user name to use on IRC server"), + N_("user name to use on server"), NULL, 0, 0, default_value, value, null_value_allowed, @@ -693,7 +693,7 @@ irc_config_server_new_option (struct t_config_file *config_file, new_option = weechat_config_new_option ( config_file, section, option_name, "string", - N_("real name to use on IRC server"), + N_("real name to use on server"), NULL, 0, 0, default_value, value, null_value_allowed, @@ -1181,7 +1181,7 @@ irc_config_init () irc_config_network_send_unknown_commands = weechat_config_new_option ( irc_config_file, ptr_section, "send_unknown_commands", "boolean", - N_("send unknown commands to IRC server"), + N_("send unknown commands to server"), NULL, 0, 0, "off", NULL, 0, NULL, NULL, &irc_config_change_network_send_unknown_commands, NULL, NULL, NULL); diff --git a/src/plugins/irc/irc-config.h b/src/plugins/irc/irc-config.h index f12115958..2ea24f5fc 100644 --- a/src/plugins/irc/irc-config.h +++ b/src/plugins/irc/irc-config.h @@ -26,14 +26,6 @@ #define IRC_CONFIG_DISPLAY_AWAY_LOCAL 1 #define IRC_CONFIG_DISPLAY_AWAY_CHANNEL 2 -#define IRC_CONFIG_SERVER_DEFAULT_AUTOCONNECT 0 -#define IRC_CONFIG_SERVER_DEFAULT_AUTORECONNECT 1 -#define IRC_CONFIG_SERVER_DEFAULT_AUTORECONNECT_DELAY 30 -#define IRC_CONFIG_SERVER_DEFAULT_IPV6 0 -#define IRC_CONFIG_SERVER_DEFAULT_SSL 0 -#define IRC_CONFIG_SERVER_DEFAULT_COMMAND_DELAY 1 -#define IRC_CONFIG_SERVER_DEFAULT_AUTOREJOIN 0 - extern struct t_config_file *irc_config_file; extern struct t_config_section *irc_config_section_server_default; diff --git a/src/plugins/irc/irc-display.c b/src/plugins/irc/irc-display.c index c804a6dcc..4099ae60f 100644 --- a/src/plugins/irc/irc-display.c +++ b/src/plugins/irc/irc-display.c @@ -113,7 +113,7 @@ irc_display_away (struct t_irc_server *server, const char *string1, const char * } /* - * irc_display_server: display server description + * irc_display_server: display server infos */ void diff --git a/src/plugins/irc/irc-ignore.c b/src/plugins/irc/irc-ignore.c index f3ad0b791..e116ec8bd 100644 --- a/src/plugins/irc/irc-ignore.c +++ b/src/plugins/irc/irc-ignore.c @@ -183,7 +183,7 @@ irc_ignore_new (const char *mask, const char *server, const char *channel) int irc_ignore_check (struct t_irc_server *server, struct t_irc_channel *channel, - char *nick, char *host) + const char *nick, const char *host) { struct t_irc_ignore *ptr_ignore; int server_match, channel_match, regex_match; diff --git a/src/plugins/irc/irc-ignore.h b/src/plugins/irc/irc-ignore.h index ff116cd8d..5f751a4f9 100644 --- a/src/plugins/irc/irc-ignore.h +++ b/src/plugins/irc/irc-ignore.h @@ -48,7 +48,7 @@ extern struct t_irc_ignore *irc_ignore_new (const char *mask, const char *channel); extern int irc_ignore_check (struct t_irc_server *server, struct t_irc_channel *channel, - char *nick, char *host); + const char *nick, const char *host); extern void irc_ignore_free (struct t_irc_ignore *ignore); extern void irc_ignore_free_all (); extern int irc_ignore_add_to_infolist (struct t_infolist *infolist, diff --git a/src/plugins/irc/irc-info.c b/src/plugins/irc/irc-info.c index 87911d87c..83c516d55 100644 --- a/src/plugins/irc/irc-info.c +++ b/src/plugins/irc/irc-info.c @@ -63,7 +63,8 @@ const char * irc_info_get_info_cb (void *data, const char *info_name, const char *arguments) { - char *pos_comma, *pos_comma2, *server, *channel, *host, *nick; + char *pos_comma, *pos_comma2, *server, *channel, *host; + const char *nick; static char str_true[2] = "1"; struct t_irc_server *ptr_server; struct t_irc_channel *ptr_channel; @@ -361,7 +362,7 @@ irc_info_get_infolist_cb (void *data, const char *infolist_name, void irc_info_init () { - /* irc info hooks */ + /* info hooks */ weechat_hook_info ("irc_is_channel", N_("1 if string is an IRC channel"), &irc_info_get_info_cb, NULL); weechat_hook_info ("irc_nick_from_host", N_("get nick from IRC host"), @@ -369,7 +370,7 @@ irc_info_init () weechat_hook_info ("irc_buffer", N_("get buffer pointer for an IRC server/channel"), &irc_info_get_info_cb, NULL); - /* irc infolist hooks */ + /* infolist hooks */ weechat_hook_infolist ("irc_server", N_("list of IRC servers"), &irc_info_get_infolist_cb, NULL); weechat_hook_infolist ("irc_channel", N_("list of channels for an IRC server"), diff --git a/src/plugins/irc/irc-input.h b/src/plugins/irc/irc-input.h index d98406a87..2366c12c7 100644 --- a/src/plugins/irc/irc-input.h +++ b/src/plugins/irc/irc-input.h @@ -20,6 +20,10 @@ #ifndef __WEECHAT_IRC_INPUT_H #define __WEECHAT_IRC_INPUT_H 1 +struct t_gui_buffer; + +extern void irc_input_user_message_display (struct t_gui_buffer *buffer, + const char *text); extern int irc_input_data_cb (void *data, struct t_gui_buffer *buffer, const char *input_data); diff --git a/src/plugins/irc/irc-nick.c b/src/plugins/irc/irc-nick.c index 2161c6fb8..549cad1f0 100644 --- a/src/plugins/irc/irc-nick.c +++ b/src/plugins/irc/irc-nick.c @@ -34,8 +34,8 @@ /* * irc_nick_valid: check if a nick pointer exists for a channel - * return 1 if nick exists - * 0 if nick is not found + * return 1 if nick exists + * 0 if nick is not found */ int @@ -419,7 +419,9 @@ irc_nick_free_all (struct t_irc_channel *channel) /* remove all nicks for the channel */ while (channel->nicks) + { irc_nick_free (channel, channel->nicks); + } /* sould be zero, but prevent any bug :D */ channel->nicks_count = 0; @@ -443,6 +445,8 @@ irc_nick_search (struct t_irc_channel *channel, const char *nickname) if (weechat_strcasecmp (ptr_nick->name, nickname) == 0) return ptr_nick; } + + /* nick not found */ return NULL; } diff --git a/src/plugins/irc/irc-nick.h b/src/plugins/irc/irc-nick.h index 1eaeeaa23..bdbbeac74 100644 --- a/src/plugins/irc/irc-nick.h +++ b/src/plugins/irc/irc-nick.h @@ -61,10 +61,14 @@ extern int irc_nick_valid (struct t_irc_channel *channel, extern const char *irc_nick_find_color (struct t_irc_nick *nick); extern struct t_irc_nick *irc_nick_new (struct t_irc_server *server, struct t_irc_channel *channel, - const char *nick_name, int is_chanowner, - int is_chanadmin, int is_chanadmin2, - int is_op, int is_halfop, - int has_voice, int is_chanuser, + const char *nick_name, + int is_chanowner, + int is_chanadmin, + int is_chanadmin2, + int is_op, + int is_halfop, + int has_voice, + int is_chanuser, int is_away); extern void irc_nick_change (struct t_irc_server *server, struct t_irc_channel *channel, diff --git a/src/plugins/irc/irc-protocol.c b/src/plugins/irc/irc-protocol.c index f45b4ae91..5d8af3b3b 100644 --- a/src/plugins/irc/irc-protocol.c +++ b/src/plugins/irc/irc-protocol.c @@ -49,7 +49,7 @@ * irc_protocol_get_nick_from_host: get nick from host in an IRC message */ -char * +const char * irc_protocol_get_nick_from_host (const char *host) { static char nick[128]; @@ -79,7 +79,7 @@ irc_protocol_get_nick_from_host (const char *host) * irc_protocol_get_address_from_host: get address from host in an IRC message */ -char * +const char * irc_protocol_get_address_from_host (const char *host) { static char address[256]; @@ -128,7 +128,7 @@ irc_protocol_log_level_for_command (const char *command) * irc_protocol_tags: build tags list with IRC command and/or tags */ -char * +const char * irc_protocol_tags (const char *command, const char *tags) { static char string[512]; diff --git a/src/plugins/irc/irc-protocol.h b/src/plugins/irc/irc-protocol.h index 6585140a2..3e3c68eaa 100644 --- a/src/plugins/irc/irc-protocol.h +++ b/src/plugins/irc/irc-protocol.h @@ -21,7 +21,7 @@ #define __WEECHAT_IRC_PROTOCOL_H 1 #define IRC_PROTOCOL_GET_HOST \ - char *nick, *address, *host; \ + const char *nick, *address, *host; \ if (argv[0][0] == ':') \ { \ nick = irc_protocol_get_nick_from_host (argv[0]); \ @@ -69,8 +69,8 @@ struct t_irc_protocol_msg t_irc_recv_func *recv_function; /* function called when msg is received */ }; -extern char *irc_protocol_get_nick_from_host (const char *host); -extern char *irc_protocol_tags (const char *command, const char *tags); +extern const char *irc_protocol_get_nick_from_host (const char *host); +extern const char *irc_protocol_tags (const char *command, const char *tags); extern void irc_protocol_recv_command (struct t_irc_server *server, const char *entire_line, const char *host, const char *command, diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c index 4b4709826..1ba258883 100644 --- a/src/plugins/irc/irc-server.c +++ b/src/plugins/irc/irc-server.c @@ -16,7 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* irc-server.c: connection and communication with IRC server */ +/* irc-server.c: connection and I/O communication with IRC server */ #include <stdlib.h> @@ -26,8 +26,16 @@ #include <stdarg.h> #include <string.h> #include <time.h> +#ifdef _WIN32 +#include <winsock.h> +#else #include <sys/socket.h> #include <sys/time.h> +#endif + +#ifdef HAVE_GNUTLS +#include <gnutls/gnutls.h> +#endif #include "../weechat-plugin.h" #include "irc.h" @@ -682,11 +690,8 @@ irc_server_free (struct t_irc_server *server) if (!server) return; - /* close any opened channel/private */ - while (server->channels) - { - irc_channel_free (server, server->channels); - } + /* close all channels/privates */ + irc_channel_free_all (server); /* remove server from queue */ if (last_irc_server == server) @@ -1287,8 +1292,7 @@ irc_server_msgq_add_msg (struct t_irc_server *server, const char *msg) if (!message) { weechat_printf (server->buffer, - _("%s%s: not enough memory for received IRC " - "message"), + _("%s%s: not enough memory for received message"), irc_buffer_get_server_prefix (server, "error"), IRC_PLUGIN_NAME); return; @@ -1301,8 +1305,7 @@ irc_server_msgq_add_msg (struct t_irc_server *server, const char *msg) if (!message->data) { weechat_printf (server->buffer, - _("%s%s: not enough memory for received IRC " - "message"), + _("%s%s: not enough memory for received message"), irc_buffer_get_server_prefix (server, "error"), IRC_PLUGIN_NAME); } @@ -1349,8 +1352,7 @@ irc_server_msgq_add_unterminated (struct t_irc_server *server, const char *strin if (!server->unterminated_message) { weechat_printf (server->buffer, - _("%s%s: not enough memory for received IRC " - "message"), + _("%s%s: not enough memory for received message"), irc_buffer_get_server_prefix (server, "error"), IRC_PLUGIN_NAME); } @@ -1363,8 +1365,7 @@ irc_server_msgq_add_unterminated (struct t_irc_server *server, const char *strin if (!server->unterminated_message) { weechat_printf (server->buffer, - _("%s%s: not enough memory for received IRC " - "message"), + _("%s%s: not enough memory for received message"), irc_buffer_get_server_prefix (server, "error"), IRC_PLUGIN_NAME); } @@ -1714,7 +1715,11 @@ irc_server_close_connection (struct t_irc_server *server) } if (server->sock != -1) { +#ifdef _WIN32 + closesocket (server->sock); +#else close (server->sock); +#endif server->sock = -1; } @@ -1813,7 +1818,7 @@ irc_server_switch_address (struct t_irc_server *server) IRC_PLUGIN_NAME, server->addresses_array[server->index_current_address], server->ports_array[server->index_current_address]); - irc_server_connect (server, 0); + irc_server_connect (server); } else irc_server_reconnect_schedule (server); @@ -1848,11 +1853,11 @@ irc_server_connect_cb (void *arg_server, int status, const char *ip_address) IRC_PLUGIN_NAME, server->addresses_array[server->index_current_address], (server->current_ip) ? server->current_ip : "?"); - irc_server_login (server); server->hook_fd = weechat_hook_fd (server->sock, 1, 0, 0, &irc_server_recv_cb, server); + irc_server_login (server); break; case WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND: weechat_printf (server->buffer, @@ -1890,8 +1895,8 @@ irc_server_connect_cb (void *arg_server, int status, const char *ip_address) _("%s%s: proxy fails to establish " "connection to server " "(check username/password if used " - "and if IRC server address/port is " - "allowed by proxy)"), + "and if server address/port is allowed by " + "proxy)"), irc_buffer_get_server_prefix (server, "error"), IRC_PLUGIN_NAME); irc_server_close_connection (server); @@ -2054,20 +2059,13 @@ irc_server_set_current_server (struct t_irc_server *server) */ int -irc_server_connect (struct t_irc_server *server, int disable_autojoin) +irc_server_connect (struct t_irc_server *server) { int set, length; char *option_name, charset_modifier[256]; struct t_config_option *proxy_type, *proxy_ipv6, *proxy_address, *proxy_port; const char *proxy, *str_proxy_type, *str_proxy_address; - proxy_type = NULL; - proxy_ipv6 = NULL; - proxy_address = NULL; - proxy_port = NULL; - str_proxy_type = NULL; - str_proxy_address = NULL; - if (!server->buffer) { if (weechat_config_boolean (irc_config_look_one_server_buffer) @@ -2104,6 +2102,23 @@ irc_server_connect (struct t_irc_server *server, int disable_autojoin) "/command irc /server switch"); } + if (!server->addresses_array) + { + weechat_printf (server->buffer, + _("%s%s: addresses not defined for server \"%s\", " + "cannot connect"), + irc_buffer_get_server_prefix (server, "error"), + IRC_PLUGIN_NAME, server->name); + return 0; + } + + proxy_type = NULL; + proxy_ipv6 = NULL; + proxy_address = NULL; + proxy_port = NULL; + str_proxy_type = NULL; + str_proxy_address = NULL; + proxy = IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_PROXY); if (proxy && proxy[0]) { @@ -2149,16 +2164,6 @@ irc_server_connect (struct t_irc_server *server, int disable_autojoin) } } - if (!server->addresses_array) - { - weechat_printf (server->buffer, - _("%s%s: addresses not defined for server \"%s\", " - "cannot connect"), - irc_buffer_get_server_prefix (server, "error"), - IRC_PLUGIN_NAME, server->name); - return 0; - } - if (!server->nicks_array) { weechat_printf (server->buffer, @@ -2173,7 +2178,7 @@ irc_server_connect (struct t_irc_server *server, int disable_autojoin) if (weechat_config_boolean (IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_SSL))) { weechat_printf (server->buffer, - _("%s%s: cannot connect with SSL since WeeChat " + _("%s%s: cannot connect with SSL because WeeChat " "was not built with GnuTLS support"), irc_buffer_get_server_prefix (server, "error"), IRC_PLUGIN_NAME); @@ -2233,7 +2238,7 @@ irc_server_connect (struct t_irc_server *server, int disable_autojoin) " (SSL)" : ""); } - /* close connection if open */ + /* close connection if opened */ irc_server_close_connection (server); /* create socket and set options */ @@ -2289,8 +2294,6 @@ irc_server_connect (struct t_irc_server *server, int disable_autojoin) server->ssl_connected = 1; #endif - server->disable_autojoin = disable_autojoin; - server->hook_connect = weechat_hook_connect (proxy, server->addresses_array[server->index_current_address], server->ports_array[server->index_current_address], @@ -2302,7 +2305,7 @@ irc_server_connect (struct t_irc_server *server, int disable_autojoin) NULL, #endif IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_LOCAL_HOSTNAME), - irc_server_connect_cb, + &irc_server_connect_cb, server); /* send signal "irc_server_connecting" with server name */ @@ -2326,7 +2329,7 @@ irc_server_reconnect (struct t_irc_server *server) server->reconnect_start = 0; server->index_current_address = 0; - if (irc_server_connect (server, 0)) + if (irc_server_connect (server)) server->reconnect_join = 1; else irc_server_reconnect_schedule (server); @@ -2337,17 +2340,16 @@ irc_server_reconnect (struct t_irc_server *server) */ void -irc_server_auto_connect (int auto_connect) +irc_server_auto_connect () { struct t_irc_server *ptr_server; for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server) { - if (auto_connect - && IRC_SERVER_OPTION_BOOLEAN(ptr_server, IRC_SERVER_OPTION_AUTOCONNECT)) + if (IRC_SERVER_OPTION_BOOLEAN(ptr_server, IRC_SERVER_OPTION_AUTOCONNECT)) { - if (!irc_server_connect (ptr_server, 0)) + if (!irc_server_connect (ptr_server)) irc_server_reconnect_schedule (ptr_server); } } @@ -2364,7 +2366,8 @@ irc_server_disconnect (struct t_irc_server *server, int reconnect) if (server->is_connected) { - /* write disconnection message on each channel/private buffer */ + /* remove all nicks and write disconnection message on each + channel/private buffer */ for (ptr_channel = server->channels; ptr_channel; ptr_channel = ptr_channel->next_channel) { @@ -2379,10 +2382,12 @@ irc_server_disconnect (struct t_irc_server *server, int reconnect) irc_server_close_connection (server); if (server->buffer) + { weechat_printf (server->buffer, _("%s%s: disconnected from server"), irc_buffer_get_server_prefix (server, NULL), IRC_PLUGIN_NAME); + } server->index_current_address = 0; if (server->nick_modes) @@ -2577,7 +2582,7 @@ irc_server_get_pv_count (struct t_irc_server *server) for (ptr_channel = server->channels; ptr_channel; ptr_channel = ptr_channel->next_channel) { - if (ptr_channel->type != IRC_CHANNEL_TYPE_CHANNEL) + if (ptr_channel->type == IRC_CHANNEL_TYPE_PRIVATE) count++; } return count; @@ -2888,21 +2893,12 @@ irc_server_add_to_infolist (struct t_infolist *infolist, && (irc_current_server != server)) ? 0 : 1)) return 0; - if (!weechat_infolist_new_var_integer (ptr_item, "autoconnect", - IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_AUTOCONNECT))) - return 0; - if (!weechat_infolist_new_var_integer (ptr_item, "autoreconnect", - IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_AUTORECONNECT))) - return 0; - if (!weechat_infolist_new_var_integer (ptr_item, "autoreconnect_delay", - IRC_SERVER_OPTION_INTEGER(server, IRC_SERVER_OPTION_AUTORECONNECT_DELAY))) + if (!weechat_infolist_new_var_string (ptr_item, "addresses", + IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_ADDRESSES))) return 0; if (!weechat_infolist_new_var_string (ptr_item, "proxy", IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_PROXY))) return 0; - if (!weechat_infolist_new_var_string (ptr_item, "addresses", - IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_ADDRESSES))) - return 0; if (!weechat_infolist_new_var_integer (ptr_item, "ipv6", IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_IPV6))) return 0; @@ -2912,6 +2908,15 @@ irc_server_add_to_infolist (struct t_infolist *infolist, if (!weechat_infolist_new_var_string (ptr_item, "password", IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_PASSWORD))) return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "autoconnect", + IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_AUTOCONNECT))) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "autoreconnect", + IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_AUTORECONNECT))) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "autoreconnect_delay", + IRC_SERVER_OPTION_INTEGER(server, IRC_SERVER_OPTION_AUTORECONNECT_DELAY))) + return 0; if (!weechat_infolist_new_var_string (ptr_item, "nicks", IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_NICKS))) return 0; @@ -2940,6 +2945,8 @@ irc_server_add_to_infolist (struct t_infolist *infolist, return 0; if (!weechat_infolist_new_var_integer (ptr_item, "index_current_address", server->index_current_address)) return 0; + if (!weechat_infolist_new_var_string (ptr_item, "current_ip", server->current_ip)) + return 0; if (!weechat_infolist_new_var_integer (ptr_item, "sock", server->sock)) return 0; if (!weechat_infolist_new_var_integer (ptr_item, "is_connected", server->is_connected)) @@ -2999,13 +3006,13 @@ irc_server_print_log () weechat_log_printf ("[server %s (addr:0x%lx)]", ptr_server->name, ptr_server); if (weechat_config_option_is_null (ptr_server->options[IRC_SERVER_OPTION_ADDRESSES])) - weechat_log_printf (" addresses. . . . . . : null (%s)", + weechat_log_printf (" addresses. . . . . . : null ('%s')", IRC_SERVER_OPTION_STRING(ptr_server, IRC_SERVER_OPTION_ADDRESSES)); else weechat_log_printf (" addresses. . . . . . : '%s'", weechat_config_string (ptr_server->options[IRC_SERVER_OPTION_ADDRESSES])); if (weechat_config_option_is_null (ptr_server->options[IRC_SERVER_OPTION_PROXY])) - weechat_log_printf (" proxy. . . . . . . . : null (%s)", + weechat_log_printf (" proxy. . . . . . . . : null ('%s')", IRC_SERVER_OPTION_STRING(ptr_server, IRC_SERVER_OPTION_PROXY)); else weechat_log_printf (" proxy. . . . . . . . : '%s'", @@ -3053,25 +3060,25 @@ irc_server_print_log () weechat_log_printf (" autoreconnect_delay. : %d", weechat_config_integer (ptr_server->options[IRC_SERVER_OPTION_AUTORECONNECT_DELAY])); if (weechat_config_option_is_null (ptr_server->options[IRC_SERVER_OPTION_NICKS])) - weechat_log_printf (" nicks. . . . . . . . : null (%s)", + weechat_log_printf (" nicks. . . . . . . . : null ('%s')", IRC_SERVER_OPTION_STRING(ptr_server, IRC_SERVER_OPTION_NICKS)); else weechat_log_printf (" nicks. . . . . . . . : '%s'", weechat_config_string (ptr_server->options[IRC_SERVER_OPTION_NICKS])); if (weechat_config_option_is_null (ptr_server->options[IRC_SERVER_OPTION_USERNAME])) - weechat_log_printf (" username . . . . . . : null (%s)", + weechat_log_printf (" username . . . . . . : null ('%s')", IRC_SERVER_OPTION_STRING(ptr_server, IRC_SERVER_OPTION_USERNAME)); else weechat_log_printf (" username . . . . . . : '%s'", weechat_config_string (ptr_server->options[IRC_SERVER_OPTION_USERNAME])); if (weechat_config_option_is_null (ptr_server->options[IRC_SERVER_OPTION_REALNAME])) - weechat_log_printf (" realname . . . . . . : null (%s)", + weechat_log_printf (" realname . . . . . . : null ('%s')", IRC_SERVER_OPTION_STRING(ptr_server, IRC_SERVER_OPTION_REALNAME)); else weechat_log_printf (" realname . . . . . . : '%s'", weechat_config_string (ptr_server->options[IRC_SERVER_OPTION_REALNAME])); if (weechat_config_option_is_null (ptr_server->options[IRC_SERVER_OPTION_LOCAL_HOSTNAME])) - weechat_log_printf (" local_hostname . . . : null (%s)", + weechat_log_printf (" local_hostname . . . : null ('%s')", IRC_SERVER_OPTION_STRING(ptr_server, IRC_SERVER_OPTION_LOCAL_HOSTNAME)); else weechat_log_printf (" local_hostname . . . : '%s'", @@ -3087,7 +3094,7 @@ irc_server_print_log () weechat_log_printf (" command_delay. . . . : %d", weechat_config_integer (ptr_server->options[IRC_SERVER_OPTION_COMMAND_DELAY])); if (weechat_config_option_is_null (ptr_server->options[IRC_SERVER_OPTION_AUTOJOIN])) - weechat_log_printf (" autojoin . . . . . . : null (%s)", + weechat_log_printf (" autojoin . . . . . . : null ('%s')", IRC_SERVER_OPTION_STRING(ptr_server, IRC_SERVER_OPTION_AUTOJOIN)); else weechat_log_printf (" autojoin . . . . . . : '%s'", @@ -3106,11 +3113,16 @@ irc_server_print_log () weechat_log_printf (" addresses_count. . . : %d", ptr_server->addresses_count); weechat_log_printf (" addresses_array. . . : 0x%lx", ptr_server->addresses_array); weechat_log_printf (" ports_array. . . . . : 0x%lx", ptr_server->ports_array); + weechat_log_printf (" index_current_address: %d", ptr_server->index_current_address); + weechat_log_printf (" current_ip . . . . . : '%s'", ptr_server->current_ip); weechat_log_printf (" sock . . . . . . . . : %d", ptr_server->sock); weechat_log_printf (" hook_connect . . . . : 0x%lx", ptr_server->hook_connect); weechat_log_printf (" hook_fd. . . . . . . : 0x%lx", ptr_server->hook_fd); weechat_log_printf (" is_connected . . . . : %d", ptr_server->is_connected); weechat_log_printf (" ssl_connected. . . . : %d", ptr_server->ssl_connected); +#ifdef HAVE_GNUTLS + weechat_log_printf (" gnutls_sess. . . . . : 0x%lx", ptr_server->gnutls_sess); +#endif weechat_log_printf (" unterminated_message : '%s'", ptr_server->unterminated_message); weechat_log_printf (" nicks_count. . . . . : %d", ptr_server->nicks_count); weechat_log_printf (" nicks_array. . . . . : 0x%lx", ptr_server->nicks_array); @@ -3129,15 +3141,18 @@ irc_server_print_log () ptr_server->lag_check_time.tv_sec, ptr_server->lag_check_time.tv_usec); weechat_log_printf (" lag_next_check . . . : %ld", ptr_server->lag_next_check); + weechat_log_printf (" cmd_list_regexp. . . : 0x%lx", ptr_server->cmd_list_regexp); + weechat_log_printf (" queue_msg. . . . . . : %d", ptr_server->queue_msg); weechat_log_printf (" last_user_message. . : %ld", ptr_server->last_user_message); weechat_log_printf (" outqueue . . . . . . : 0x%lx", ptr_server->outqueue); weechat_log_printf (" last_outqueue. . . . : 0x%lx", ptr_server->last_outqueue); weechat_log_printf (" buffer . . . . . . . : 0x%lx", ptr_server->buffer); + weechat_log_printf (" buffer_as_string . . : 0x%lx", ptr_server->buffer_as_string); weechat_log_printf (" channels . . . . . . : 0x%lx", ptr_server->channels); weechat_log_printf (" last_channel . . . . : 0x%lx", ptr_server->last_channel); weechat_log_printf (" prev_server. . . . . : 0x%lx", ptr_server->prev_server); weechat_log_printf (" next_server. . . . . : 0x%lx", ptr_server->next_server); - + for (ptr_channel = ptr_server->channels; ptr_channel; ptr_channel = ptr_channel->next_channel) { diff --git a/src/plugins/irc/irc-server.h b/src/plugins/irc/irc-server.h index eb0b9ff53..ac6211a52 100644 --- a/src/plugins/irc/irc-server.h +++ b/src/plugins/irc/irc-server.h @@ -54,23 +54,23 @@ enum t_irc_server_option }; #define IRC_SERVER_OPTION_BOOLEAN(__server, __index) \ - ((!weechat_config_option_is_null (__server->options[__index])) ? \ + ((!weechat_config_option_is_null(__server->options[__index])) ? \ weechat_config_boolean(__server->options[__index]) : \ - ((!weechat_config_option_is_null (irc_config_server_default[__index])) ? \ + ((!weechat_config_option_is_null(irc_config_server_default[__index])) ? \ weechat_config_boolean(irc_config_server_default[__index]) \ : weechat_config_boolean_default(irc_config_server_default[__index]))) #define IRC_SERVER_OPTION_INTEGER(__server, __index) \ - ((!weechat_config_option_is_null (__server->options[__index])) ? \ + ((!weechat_config_option_is_null(__server->options[__index])) ? \ weechat_config_integer(__server->options[__index]) : \ - ((!weechat_config_option_is_null (irc_config_server_default[__index])) ? \ + ((!weechat_config_option_is_null(irc_config_server_default[__index])) ? \ weechat_config_integer(irc_config_server_default[__index]) \ : weechat_config_integer_default(irc_config_server_default[__index]))) #define IRC_SERVER_OPTION_STRING(__server, __index) \ - ((!weechat_config_option_is_null (__server->options[__index])) ? \ + ((!weechat_config_option_is_null(__server->options[__index])) ? \ weechat_config_string(__server->options[__index]) : \ - ((!weechat_config_option_is_null (irc_config_server_default[__index])) ? \ + ((!weechat_config_option_is_null(irc_config_server_default[__index])) ? \ weechat_config_string(irc_config_server_default[__index]) \ : weechat_config_string_default(irc_config_server_default[__index]))) @@ -147,7 +147,7 @@ struct t_irc_server struct t_gui_buffer *buffer; /* GUI buffer allocated for server */ char *buffer_as_string; /* used to return buffer info */ struct t_irc_channel *channels; /* opened channels on server */ - struct t_irc_channel *last_channel; /* last opened channal on server */ + struct t_irc_channel *last_channel; /* last opened channel on server */ struct t_irc_server *prev_server; /* link to previous server */ struct t_irc_server *next_server; /* link to next server */ }; @@ -194,9 +194,8 @@ extern void irc_server_set_buffer_title (struct t_irc_server *server); extern struct t_gui_buffer *irc_server_create_buffer (struct t_irc_server *server, int all_servers); extern void irc_server_set_current_server (struct t_irc_server *server); -extern int irc_server_connect (struct t_irc_server *server, - int disable_autojoin); -extern void irc_server_auto_connect (int auto_connect); +extern int irc_server_connect (struct t_irc_server *server); +extern void irc_server_auto_connect (); extern void irc_server_autojoin_channels (); extern int irc_server_recv_cb (void *arg_server); extern int irc_server_timer_cb (void *data); diff --git a/src/plugins/irc/irc-upgrade.c b/src/plugins/irc/irc-upgrade.c index 0b138b9a0..857683b69 100644 --- a/src/plugins/irc/irc-upgrade.c +++ b/src/plugins/irc/irc-upgrade.c @@ -162,7 +162,7 @@ irc_upgrade_set_buffer_callbacks () } /* - * irc_upgrade_read_cb: read callback for + * irc_upgrade_read_cb: read callback for upgrade */ int diff --git a/src/plugins/irc/irc.c b/src/plugins/irc/irc.c index 70f41fd5c..b9ee5ae04 100644 --- a/src/plugins/irc/irc.c +++ b/src/plugins/irc/irc.c @@ -146,7 +146,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) if (!irc_server_alloc_with_url (argv[i])) { weechat_printf (NULL, - _("%s%s: error with IRC server from URL " + _("%s%s: error with server from URL " "(\"%s\"), ignored"), weechat_prefix ("error"), IRC_PLUGIN_NAME, argv[i]); @@ -164,13 +164,16 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) { weechat_printf (NULL, _("%s%s: WARNING: some network connections may " - "still be open and not visible, you should " + "still be opened and not visible, you should " "restart WeeChat now (with /quit)."), weechat_prefix ("error"), IRC_PLUGIN_NAME); } } else - irc_server_auto_connect (auto_connect); + { + if (auto_connect) + irc_server_auto_connect (); + } irc_hook_timer = weechat_hook_timer (1 * 1000, 0, 0, &irc_server_timer_cb, NULL); diff --git a/src/plugins/irc/irc.h b/src/plugins/irc/irc.h index e26d5f782..de8e1ece2 100644 --- a/src/plugins/irc/irc.h +++ b/src/plugins/irc/irc.h @@ -20,10 +20,6 @@ #ifndef __WEECHAT_IRC_H #define __WEECHAT_IRC_H 1 -#ifdef HAVE_GNUTLS -#include <gnutls/gnutls.h> -#endif - #define weechat_plugin weechat_irc_plugin #define IRC_PLUGIN_NAME "irc" diff --git a/src/plugins/jabber/CMakeLists.txt b/src/plugins/jabber/CMakeLists.txt new file mode 100644 index 000000000..57ec9c56b --- /dev/null +++ b/src/plugins/jabber/CMakeLists.txt @@ -0,0 +1,45 @@ +# Copyright (c) 2009 FlashCode <flashcode@flashtux.org> +# +# 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; either version 3 of the License, or +# (at your option) any later version. +# +# 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, see <http://www.gnu.org/licenses/>. +# + +ADD_LIBRARY(jabber MODULE +jabber.c jabber.h +jabber-bar-item.c jabber-bar-item.h +jabber-buddy.c jabber-buddy.h +jabber-buffer.c jabber-buffer.h +jabber-command.c jabber-command.h +jabber-completion.c jabber-completion.h +jabber-config.c jabber-config.h +jabber-debug.c jabber-debug.h +jabber-display.c jabber-display.h +jabber-info.c jabber-info.h +jabber-input.c jabber-input.h +jabber-muc.c jabber-muc.h +jabber-server.c jabber-server.h +jabber-upgrade.c jabber-upgrade.h +jabber-xmpp.c jabber-xmpp.h) +SET_TARGET_PROPERTIES(jabber PROPERTIES PREFIX "") + +CHECK_INCLUDE_FILES("regex.h" HAVE_REGEX_H) +CHECK_FUNCTION_EXISTS(regexec HAVE_REGEXEC) + +IF(GNUTLS_FOUND) + INCLUDE_DIRECTORIES(${GNUTLS_INCLUDE_PATH} ${IKSEMEL_INCLUDE_PATH}) + TARGET_LINK_LIBRARIES(jabber ${GNUTLS_LIBRARY} ${IKSEMEL_LIBRARY}) +ELSE(GNUTLS_FOUND) + TARGET_LINK_LIBRARIES(jabber ${IKSEMEL_LIBRARY}) +ENDIF(GNUTLS_FOUND) + +INSTALL(TARGETS jabber LIBRARY DESTINATION lib/${PROJECT_NAME}/plugins) diff --git a/src/plugins/jabber/Makefile.am b/src/plugins/jabber/Makefile.am new file mode 100644 index 000000000..fb8d38975 --- /dev/null +++ b/src/plugins/jabber/Makefile.am @@ -0,0 +1,55 @@ +# Copyright (c) 2009 FlashCode <flashcode@flashtux.org> +# +# 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; either version 3 of the License, or +# (at your option) any later version. +# +# 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, see <http://www.gnu.org/licenses/>. +# + +INCLUDES = -DLOCALEDIR=\"$(datadir)/locale\" $(GNUTLS_CFLAGS) $(IKSEMEL_CFLAGS) + +libdir = ${weechat_libdir}/plugins + +lib_LTLIBRARIES = jabber.la + +jabber_la_SOURCES = jabber.c \ + jabber.h \ + jabber-bar-item.c \ + jabber-bar-item.h \ + jabber-buddy.c \ + jabber-buddy.h \ + jabber-buffer.c \ + jabber-buffer.h \ + jabber-command.c \ + jabber-command.h \ + jabber-completion.c \ + jabber-completion.h \ + jabber-config.c \ + jabber-config.h \ + jabber-debug.c \ + jabber-debug.h \ + jabber-display.c \ + jabber-display.h \ + jabber-info.c \ + jabber-info.h \ + jabber-input.c \ + jabber-input.h \ + jabber-muc.c \ + jabber-muc.h \ + jabber-server.c \ + jabber-server.h \ + jabber-upgrade.c \ + jabber-upgrade.h \ + jabber-xmpp.c \ + jabber-xmpp.h + +jabber_la_LDFLAGS = -module +jabber_la_LIBADD = $(JABBER_LFLAGS) $(GNUTLS_LFLAGS) $(IKSEMEL_LFLAGS) diff --git a/src/plugins/jabber/jabber-bar-item.c b/src/plugins/jabber/jabber-bar-item.c new file mode 100644 index 000000000..83a77514b --- /dev/null +++ b/src/plugins/jabber/jabber-bar-item.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber-bar-item.c: bar items for Jabber plugin */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-buffer.h" +#include "jabber-config.h" +#include "jabber-server.h" +#include "jabber-muc.h" + + +/* + * jabber_bar_item_buffer_name: bar item with buffer name + */ + +char * +jabber_bar_item_buffer_name (void *data, struct t_gui_bar_item *item, + struct t_gui_window *window) +{ + char buf[512], buf_name[256], modes[128], away[128]; + const char *name; + int part_from_muc; + struct t_gui_buffer *buffer; + struct t_jabber_server *server; + struct t_jabber_muc *muc; + + /* make C compiler happy */ + (void) data; + (void) item; + + if (!window) + window = weechat_current_window (); + + buf_name[0] = '\0'; + modes[0] = '\0'; + away[0] = '\0'; + + buffer = weechat_window_get_pointer (window, "buffer"); + + if (buffer) + { + jabber_buffer_get_server_muc (buffer, &server, &muc); + if (server || muc) + { + if (server && !muc) + { + if (weechat_config_boolean (jabber_config_look_one_server_buffer)) + { + snprintf (buf_name, sizeof (buf_name), "%s%s[<%s%s%s>]", + _("servers"), + JABBER_COLOR_BAR_DELIM, + JABBER_COLOR_STATUS_NAME, + (jabber_current_server) ? jabber_current_server->name : "-", + JABBER_COLOR_BAR_DELIM); + } + else + { + snprintf (buf_name, sizeof (buf_name), "%s%s[%s%s%s]", + _("server"), + JABBER_COLOR_BAR_DELIM, + JABBER_COLOR_STATUS_NAME, + server->name, + JABBER_COLOR_BAR_DELIM); + } + } + else + { + if (muc) + { + part_from_muc = ((muc->type == JABBER_MUC_TYPE_MUC) + && !muc->buddies); + snprintf (buf_name, sizeof (buf_name), + "%s%s%s%s%s/%s%s%s%s", + (part_from_muc) ? JABBER_COLOR_BAR_DELIM : "", + (part_from_muc) ? "(" : "", + JABBER_COLOR_STATUS_NAME, + server->name, + JABBER_COLOR_BAR_DELIM, + JABBER_COLOR_STATUS_NAME, + muc->name, + (part_from_muc) ? JABBER_COLOR_BAR_DELIM : "", + (part_from_muc) ? ")" : ""); + if (!part_from_muc + && weechat_config_boolean (jabber_config_look_display_muc_modes) + && muc->modes && muc->modes[0] + && (strcmp (muc->modes, "+") != 0)) + { + snprintf (modes, sizeof (modes), + "%s(%s%s%s)", + JABBER_COLOR_BAR_DELIM, + JABBER_COLOR_STATUS_NAME, + muc->modes, + JABBER_COLOR_BAR_DELIM); + } + } + } + if (server && server->is_away) + { + snprintf (away, sizeof (away), " %s(%s%s%s)", + JABBER_COLOR_BAR_DELIM, + JABBER_COLOR_BAR_FG, + _("away"), + JABBER_COLOR_BAR_DELIM); + } + } + else + { + name = weechat_buffer_get_string (buffer, "name"); + if (name) + snprintf (buf_name, sizeof (buf_name), "%s", name); + } + + snprintf (buf, sizeof (buf), "%s%s%s%s", + JABBER_COLOR_STATUS_NAME, + buf_name, + modes, + away); + return strdup (buf); + } + + return NULL; +} + +/* + * jabber_bar_item_input_prompt: bar item with input prompt + */ + +char * +jabber_bar_item_input_prompt (void *data, struct t_gui_bar_item *item, + struct t_gui_window *window) +{ + struct t_gui_buffer *buffer; + struct t_jabber_server *server; + const char *local_name; + + /* make C compiler happy */ + (void) data; + (void) item; + + if (!window) + window = weechat_current_window (); + + buffer = weechat_window_get_pointer (window, "buffer"); + + if (buffer) + { + jabber_buffer_get_server_muc (buffer, &server, NULL); + if (!server) + return NULL; + + local_name = jabber_server_get_local_name (server); + + return (local_name) ? strdup (local_name) : NULL; + } + + return NULL; +} + +/* + * jabber_bar_item_init: initialize Jabber bar items + */ + +void +jabber_bar_item_init () +{ + weechat_bar_item_new ("buffer_name", &jabber_bar_item_buffer_name, NULL); + weechat_bar_item_new ("input_prompt", &jabber_bar_item_input_prompt, NULL); +} diff --git a/src/plugins/jabber/jabber-bar-item.h b/src/plugins/jabber/jabber-bar-item.h new file mode 100644 index 000000000..a73bfc65d --- /dev/null +++ b/src/plugins/jabber/jabber-bar-item.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_BAR_ITEM_H +#define __WEECHAT_JABBER_BAR_ITEM_H 1 + +extern void jabber_bar_item_init (); + +#endif /* jabber-bar-item.h */ diff --git a/src/plugins/jabber/jabber-buddy.c b/src/plugins/jabber/jabber-buddy.c new file mode 100644 index 000000000..7d2adfebe --- /dev/null +++ b/src/plugins/jabber/jabber-buddy.c @@ -0,0 +1,719 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber-buddy.c: manages buddies list for servers and MUCs */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-buddy.h" +#include "jabber-config.h" +#include "jabber-server.h" +#include "jabber-muc.h" + + +/* + * jabber_buddy_valid: check if a buddy pointer exists for a server or a muc + * return 1 if buddy exists + * 0 if buddy is not found + */ + +int +jabber_buddy_valid (struct t_jabber_server *server, struct t_jabber_muc *muc, + struct t_jabber_buddy *buddy) +{ + struct t_jabber_buddy *ptr_buddy; + + if (server) + { + for (ptr_buddy = server->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + if (ptr_buddy == buddy) + return 1; + } + } + + if (muc) + { + for (ptr_buddy = muc->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + if (ptr_buddy == buddy) + return 1; + } + } + + /* buddy not found */ + return 0; +} + +/* + * jabber_buddy_find_color: find a color for a buddy (according to buddy letters) + */ + +const char * +jabber_buddy_find_color (struct t_jabber_buddy *buddy) +{ + int i, color; + char color_name[64]; + + color = 0; + for (i = strlen (buddy->name) - 1; i >= 0; i--) + { + color += (int)(buddy->name[i]); + } + color = (color % + weechat_config_integer (weechat_config_get ("weechat.look.color_nicks_number"))); + + snprintf (color_name, sizeof (color_name), + "chat_buddy_color%02d", color + 1); + + return weechat_color (color_name); +} + +/* + * jabber_buddy_get_gui_infos: get GUI infos for a buddy (sort_index, prefix, + * prefix color) + */ + +void +jabber_buddy_get_gui_infos (struct t_jabber_buddy *buddy, + char *prefix, int *prefix_color, + struct t_gui_buffer *buffer, + struct t_gui_nick_group **group) +{ + if (buddy->flags & JABBER_BUDDY_CHANOWNER) + { + if (prefix) + *prefix = '~'; + if (prefix_color) + *prefix_color = 1; + if (buffer && group) + *group = weechat_nicklist_search_group (buffer, NULL, + JABBER_BUDDY_GROUP_OP); + } + else if (buddy->flags & JABBER_BUDDY_CHANADMIN) + { + if (prefix) + *prefix = '&'; + if (prefix_color) + *prefix_color = 1; + if (buffer && group) + *group = weechat_nicklist_search_group (buffer, NULL, + JABBER_BUDDY_GROUP_OP); + } + else if (buddy->flags & JABBER_BUDDY_CHANADMIN2) + { + if (prefix) + *prefix = '!'; + if (prefix_color) + *prefix_color = 1; + if (buffer && group) + *group = weechat_nicklist_search_group (buffer, NULL, + JABBER_BUDDY_GROUP_OP); + } + else if (buddy->flags & JABBER_BUDDY_OP) + { + if (prefix) + *prefix = '@'; + if (prefix_color) + *prefix_color = 1; + if (buffer && group) + *group = weechat_nicklist_search_group (buffer, NULL, + JABBER_BUDDY_GROUP_OP); + } + else if (buddy->flags & JABBER_BUDDY_HALFOP) + { + if (prefix) + *prefix = '%'; + if (prefix_color) + *prefix_color = 2; + if (buffer && group) + *group = weechat_nicklist_search_group (buffer, NULL, + JABBER_BUDDY_GROUP_HALFOP); + } + else if (buddy->flags & JABBER_BUDDY_VOICE) + { + if (prefix) + *prefix = '+'; + if (prefix_color) + *prefix_color = 3; + if (buffer && group) + *group = weechat_nicklist_search_group (buffer, NULL, + JABBER_BUDDY_GROUP_VOICE); + } + else if (buddy->flags & JABBER_BUDDY_CHANUSER) + { + if (prefix) + *prefix = '-'; + if (prefix_color) + *prefix_color = 4; + if (buffer && group) + *group = weechat_nicklist_search_group (buffer, NULL, + JABBER_BUDDY_GROUP_CHANUSER); + } + else + { + if (prefix) + *prefix = ' '; + if (prefix_color) + *prefix_color = 0; + if (buffer && group) + *group = weechat_nicklist_search_group (buffer, NULL, + JABBER_BUDDY_GROUP_NORMAL); + } +} + +/* + * jabber_buddy_new: allocate a new buddy for a muc and add it to the buddy list + */ + +struct t_jabber_buddy * +jabber_buddy_new (struct t_jabber_server *server, struct t_jabber_muc *muc, + const char *buddy_name, int is_chanowner, int is_chanadmin, + int is_chanadmin2, int is_op, int is_halfop, int has_voice, + int is_chanuser, int is_away) +{ + struct t_jabber_buddy *new_buddy, *ptr_buddy; + char prefix, str_prefix_color[64]; + const char *local_name; + int prefix_color; + struct t_gui_buffer *ptr_buffer; + struct t_gui_nick_group *ptr_group; + + ptr_buffer = (muc) ? muc->buffer : server->buffer; + + /* buddy already exists on this muc? */ + if (muc) + ptr_buddy = jabber_buddy_search (NULL, muc, buddy_name); + else + ptr_buddy = jabber_buddy_search (server, NULL, buddy_name); + if (ptr_buddy) + { + /* remove old buddy from buddylist */ + jabber_buddy_get_gui_infos (ptr_buddy, &prefix, + &prefix_color, ptr_buffer, &ptr_group); + weechat_nicklist_remove_nick (ptr_buffer, + weechat_nicklist_search_nick (ptr_buffer, + ptr_group, + ptr_buddy->name)); + + /* update buddy */ + JABBER_BUDDY_SET_FLAG(ptr_buddy, is_chanowner, JABBER_BUDDY_CHANOWNER); + JABBER_BUDDY_SET_FLAG(ptr_buddy, is_chanadmin, JABBER_BUDDY_CHANADMIN); + JABBER_BUDDY_SET_FLAG(ptr_buddy, is_chanadmin2, JABBER_BUDDY_CHANADMIN2); + JABBER_BUDDY_SET_FLAG(ptr_buddy, is_op, JABBER_BUDDY_OP); + JABBER_BUDDY_SET_FLAG(ptr_buddy, is_halfop, JABBER_BUDDY_HALFOP); + JABBER_BUDDY_SET_FLAG(ptr_buddy, has_voice, JABBER_BUDDY_VOICE); + JABBER_BUDDY_SET_FLAG(ptr_buddy, is_chanuser, JABBER_BUDDY_CHANUSER); + JABBER_BUDDY_SET_FLAG(ptr_buddy, is_away, JABBER_BUDDY_AWAY); + + /* add new buddy in buddylist */ + jabber_buddy_get_gui_infos (ptr_buddy, &prefix, + &prefix_color, ptr_buffer, &ptr_group); + snprintf (str_prefix_color, sizeof (str_prefix_color), + "weechat.color.nicklist_prefix%d", + prefix_color); + weechat_nicklist_add_nick (ptr_buffer, ptr_group, + ptr_buddy->name, + (is_away) ? + "weechat.color.nicklist_away" : "bar_fg", + prefix, str_prefix_color, 1); + + return ptr_buddy; + } + + /* alloc memory for new buddy */ + if ((new_buddy = malloc (sizeof (*new_buddy))) == NULL) + return NULL; + + /* initialize new buddy */ + new_buddy->name = strdup (buddy_name); + new_buddy->host = NULL; + new_buddy->flags = 0; + JABBER_BUDDY_SET_FLAG(new_buddy, is_chanowner, JABBER_BUDDY_CHANOWNER); + JABBER_BUDDY_SET_FLAG(new_buddy, is_chanadmin, JABBER_BUDDY_CHANADMIN); + JABBER_BUDDY_SET_FLAG(new_buddy, is_chanadmin2, JABBER_BUDDY_CHANADMIN2); + JABBER_BUDDY_SET_FLAG(new_buddy, is_op, JABBER_BUDDY_OP); + JABBER_BUDDY_SET_FLAG(new_buddy, is_halfop, JABBER_BUDDY_HALFOP); + JABBER_BUDDY_SET_FLAG(new_buddy, has_voice, JABBER_BUDDY_VOICE); + JABBER_BUDDY_SET_FLAG(new_buddy, is_chanuser, JABBER_BUDDY_CHANUSER); + JABBER_BUDDY_SET_FLAG(new_buddy, is_away, JABBER_BUDDY_AWAY); + local_name = jabber_server_get_local_name (server); + if (weechat_strcasecmp (new_buddy->name, local_name) == 0) + new_buddy->color = JABBER_COLOR_CHAT_NICK_SELF; + else + new_buddy->color = jabber_buddy_find_color (new_buddy); + + /* add buddy to end of list */ + if (muc) + { + new_buddy->prev_buddy = muc->last_buddy; + if (muc->buddies) + muc->last_buddy->next_buddy = new_buddy; + else + muc->buddies = new_buddy; + muc->last_buddy = new_buddy; + new_buddy->next_buddy = NULL; + + muc->buddies_count++; + + muc->nick_completion_reset = 1; + } + else + { + new_buddy->prev_buddy = server->last_buddy; + if (server->buddies) + server->last_buddy->next_buddy = new_buddy; + else + server->buddies = new_buddy; + server->last_buddy = new_buddy; + new_buddy->next_buddy = NULL; + + server->buddies_count++; + } + + /* add buddy to buffer buddylist */ + jabber_buddy_get_gui_infos (new_buddy, &prefix, &prefix_color, + ptr_buffer, &ptr_group); + snprintf (str_prefix_color, sizeof (str_prefix_color), + "weechat.color.nicklist_prefix%d", + prefix_color); + weechat_nicklist_add_nick (ptr_buffer, ptr_group, + new_buddy->name, + (is_away) ? + "weechat.color.nicklist_away" : "bar_fg", + prefix, str_prefix_color, 1); + + /* all is ok, return address of new buddy */ + return new_buddy; +} + +/* + * jabber_buddy_change: change buddyname + */ + +void +jabber_buddy_change (struct t_jabber_server *server, struct t_jabber_muc *muc, + struct t_jabber_buddy *buddy, const char *new_buddy) +{ + int buddy_is_me, prefix_color; + struct t_gui_buffer *ptr_buffer; + struct t_gui_nick_group *ptr_group; + char prefix, str_prefix_color[64]; + const char *local_name; + + ptr_buffer = (muc) ? muc->buffer : server->buffer; + + /* remove buddy from buddylist */ + jabber_buddy_get_gui_infos (buddy, &prefix, &prefix_color, + ptr_buffer, &ptr_group); + weechat_nicklist_remove_nick (ptr_buffer, + weechat_nicklist_search_nick (ptr_buffer, + ptr_group, + buddy->name)); + + /* update buddies speaking */ + local_name = jabber_server_get_local_name (server); + buddy_is_me = (strcmp (buddy->name, local_name) == 0) ? 1 : 0; + if (muc && !buddy_is_me) + jabber_muc_buddy_speaking_rename (muc, buddy->name, new_buddy); + + /* change buddyname */ + if (buddy->name) + free (buddy->name); + buddy->name = strdup (new_buddy); + if (buddy_is_me) + buddy->color = JABBER_COLOR_CHAT_NICK_SELF; + else + buddy->color = jabber_buddy_find_color (buddy); + + /* add buddy in buddylist */ + jabber_buddy_get_gui_infos (buddy, &prefix, &prefix_color, + ptr_buffer, &ptr_group); + snprintf (str_prefix_color, sizeof (str_prefix_color), + "weechat.color.nicklist_prefix%d", + prefix_color); + weechat_nicklist_add_nick (ptr_buffer, ptr_group, + buddy->name, "bar_fg", + prefix, str_prefix_color, 1); +} + +/* + * jabber_buddy_set: set a flag for a buddy + */ + +void +jabber_buddy_set (struct t_jabber_server *server, struct t_jabber_muc *muc, + struct t_jabber_buddy *buddy, int set, int flag) +{ + struct t_gui_buffer *ptr_buffer; + struct t_gui_nick_group *ptr_group; + char prefix, str_prefix_color[64]; + int prefix_color; + + if (server || muc) + { + ptr_buffer = (muc) ? muc->buffer : server->buffer; + + /* remove buddy from buddylist */ + jabber_buddy_get_gui_infos (buddy, &prefix, &prefix_color, + ptr_buffer, &ptr_group); + weechat_nicklist_remove_nick (ptr_buffer, + weechat_nicklist_search_nick (ptr_buffer, + ptr_group, + buddy->name)); + + /* set flag */ + JABBER_BUDDY_SET_FLAG(buddy, set, flag); + + /* add buddy in buddylist */ + jabber_buddy_get_gui_infos (buddy, &prefix, &prefix_color, + ptr_buffer, &ptr_group); + snprintf (str_prefix_color, sizeof (str_prefix_color), + "weechat.color.nicklist_prefix%d", + prefix_color); + weechat_nicklist_add_nick (ptr_buffer, ptr_group, + buddy->name, + (buddy->flags & JABBER_BUDDY_AWAY) ? + "weechat.color.nicklist_away" : "bar_fg", + prefix, str_prefix_color, 1); + } +} + +/* + * jabber_buddy_free: free a buddy and remove it from buddies list + */ + +void +jabber_buddy_free (struct t_jabber_server *server, struct t_jabber_muc *muc, + struct t_jabber_buddy *buddy) +{ + struct t_gui_buffer *ptr_buffer; + struct t_gui_nick_group *ptr_group; + struct t_jabber_buddy *new_buddies; + char prefix; + int prefix_color; + + if ((!server && !muc) || !buddy) + return; + + ptr_buffer = (muc) ? muc->buffer : server->buffer; + + /* remove buddy from buddylist */ + jabber_buddy_get_gui_infos (buddy, &prefix, &prefix_color, + ptr_buffer, &ptr_group); + weechat_nicklist_remove_nick (ptr_buffer, + weechat_nicklist_search_nick (ptr_buffer, + ptr_group, + buddy->name)); + + /* remove buddy */ + if (muc) + { + if (muc->last_buddy == buddy) + muc->last_buddy = buddy->prev_buddy; + if (buddy->prev_buddy) + { + (buddy->prev_buddy)->next_buddy = buddy->next_buddy; + new_buddies = muc->buddies; + } + else + new_buddies = buddy->next_buddy; + if (buddy->next_buddy) + (buddy->next_buddy)->prev_buddy = buddy->prev_buddy; + muc->buddies_count--; + } + else + { + if (server->last_buddy == buddy) + server->last_buddy = buddy->prev_buddy; + if (buddy->prev_buddy) + { + (buddy->prev_buddy)->next_buddy = buddy->next_buddy; + new_buddies = server->buddies; + } + else + new_buddies = buddy->next_buddy; + if (buddy->next_buddy) + (buddy->next_buddy)->prev_buddy = buddy->prev_buddy; + server->buddies_count--; + } + + /* free data */ + if (buddy->name) + free (buddy->name); + if (buddy->host) + free (buddy->host); + + free (buddy); + + if (muc) + { + muc->buddies = new_buddies; + muc->nick_completion_reset = 1; + } + else + { + server->buddies = new_buddies; + } +} + +/* + * jabber_buddy_free_all: free all allocated buddies for a muc + */ + +void +jabber_buddy_free_all (struct t_jabber_server *server, + struct t_jabber_muc *muc) +{ + if (server) + { + while (server->buddies) + { + jabber_buddy_free (server, NULL, server->buddies); + } + /* sould be zero, but prevent any bug :D */ + server->buddies_count = 0; + } + + if (muc) + { + while (muc->buddies) + { + jabber_buddy_free (NULL, muc, muc->buddies); + } + /* sould be zero, but prevent any bug :D */ + muc->buddies_count = 0; + } +} + +/* + * jabber_buddy_search: returns pointer on a buddy + */ + +struct t_jabber_buddy * +jabber_buddy_search (struct t_jabber_server *server, struct t_jabber_muc *muc, + const char *buddyname) +{ + struct t_jabber_buddy *ptr_buddy; + + if (!buddyname) + return NULL; + + if (server) + { + for (ptr_buddy = server->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + if (weechat_strcasecmp (ptr_buddy->name, buddyname) == 0) + return ptr_buddy; + } + } + + if (muc) + { + for (ptr_buddy = muc->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + if (weechat_strcasecmp (ptr_buddy->name, buddyname) == 0) + return ptr_buddy; + } + } + + /* buddy not found */ + return NULL; +} + +/* + * jabber_buddy_count: returns number of buddies (total, op, halfop, voice) on + * a server or MUC + */ + +void +jabber_buddy_count (struct t_jabber_server *server, struct t_jabber_muc *muc, + int *total, int *count_op, int *count_halfop, + int *count_voice, int *count_normal) +{ + struct t_jabber_buddy *ptr_buddy; + + (*total) = 0; + (*count_op) = 0; + (*count_halfop) = 0; + (*count_voice) = 0; + (*count_normal) = 0; + + if (server || muc) + { + for (ptr_buddy = (muc) ? muc->buddies : server->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + (*total)++; + if ((ptr_buddy->flags & JABBER_BUDDY_CHANOWNER) || + (ptr_buddy->flags & JABBER_BUDDY_CHANADMIN) || + (ptr_buddy->flags & JABBER_BUDDY_CHANADMIN2) || + (ptr_buddy->flags & JABBER_BUDDY_OP)) + (*count_op)++; + else + { + if (ptr_buddy->flags & JABBER_BUDDY_HALFOP) + (*count_halfop)++; + else + { + if (ptr_buddy->flags & JABBER_BUDDY_VOICE) + (*count_voice)++; + else + (*count_normal)++; + } + } + } + } +} + +/* + * jabber_buddy_set_away: set/unset away status for a muc + */ + +void +jabber_buddy_set_away (struct t_jabber_server *server, + struct t_jabber_muc *muc, + struct t_jabber_buddy *buddy, int is_away) +{ + if (((is_away) && (!(buddy->flags & JABBER_BUDDY_AWAY))) || + ((!is_away) && (buddy->flags & JABBER_BUDDY_AWAY))) + { + if (muc) + jabber_buddy_set (NULL, muc, buddy, is_away, JABBER_BUDDY_AWAY); + else + jabber_buddy_set (server, NULL, buddy, is_away, JABBER_BUDDY_AWAY); + } +} + +/* + * jabber_buddy_as_prefix: return string with buddy to display as prefix on + * buffer (string will end by a tab) + */ + +char * +jabber_buddy_as_prefix (struct t_jabber_buddy *buddy, const char *buddyname, + const char *force_color) +{ + static char result[256]; + char prefix[2], str_prefix_color[64]; + int prefix_color; + + prefix[0] = '\0'; + prefix[1] = '\0'; + if (weechat_config_boolean (weechat_config_get ("weechat.look.nickmode"))) + { + if (buddy) + { + jabber_buddy_get_gui_infos (buddy, &prefix[0], &prefix_color, NULL, NULL); + if ((prefix[0] == ' ') + && !weechat_config_boolean (weechat_config_get ("weechat.look.nickmode_empty"))) + prefix[0] = '\0'; + snprintf (str_prefix_color, sizeof (str_prefix_color), + "weechat.color.nicklist_prefix%d", + prefix_color); + } + else + { + prefix[0] = (weechat_config_boolean (weechat_config_get ("weechat.look.nickmode_empty"))) ? + ' ' : '\0'; + snprintf (str_prefix_color, sizeof (str_prefix_color), + "weechat.color.chat"); + } + } + else + { + prefix[0] = '\0'; + snprintf (str_prefix_color, sizeof (str_prefix_color), "chat"); + } + + snprintf (result, sizeof (result), "%s%s%s%s%s%s%s%s\t", + (weechat_config_string (jabber_config_look_nick_prefix) + && weechat_config_string (jabber_config_look_nick_prefix)[0]) ? + JABBER_COLOR_CHAT_DELIMITERS : "", + (weechat_config_string (jabber_config_look_nick_prefix) + && weechat_config_string (jabber_config_look_nick_prefix)[0]) ? + weechat_config_string (jabber_config_look_nick_prefix) : "", + weechat_color(weechat_config_string(weechat_config_get(str_prefix_color))), + prefix, + (force_color) ? force_color : ((buddy) ? buddy->color : JABBER_COLOR_CHAT_NICK), + (buddy) ? buddy->name : buddyname, + (weechat_config_string (jabber_config_look_nick_suffix) + && weechat_config_string (jabber_config_look_nick_suffix)[0]) ? + JABBER_COLOR_CHAT_DELIMITERS : "", + (weechat_config_string (jabber_config_look_nick_suffix) + && weechat_config_string (jabber_config_look_nick_suffix)[0]) ? + weechat_config_string (jabber_config_look_nick_suffix) : ""); + + return result; +} + +/* + * jabber_buddy_add_to_infolist: add a buddy in an infolist + * return 1 if ok, 0 if error + */ + +int +jabber_buddy_add_to_infolist (struct t_infolist *infolist, + struct t_jabber_buddy *buddy) +{ + struct t_infolist_item *ptr_item; + + if (!infolist || !buddy) + return 0; + + ptr_item = weechat_infolist_new_item (infolist); + if (!ptr_item) + return 0; + + if (!weechat_infolist_new_var_string (ptr_item, "name", buddy->name)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "host", buddy->host)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "flags", buddy->flags)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "color", buddy->color)) + return 0; + + return 1; +} + +/* + * jabber_buddy_print_log: print buddy infos in log (usually for crash dump) + */ + +void +jabber_buddy_print_log (struct t_jabber_buddy *buddy) +{ + weechat_log_printf (""); + weechat_log_printf (" => buddy %s (addr:0x%lx):", buddy->name, buddy); + weechat_log_printf (" host . . . . . : %s", buddy->host); + weechat_log_printf (" flags. . . . . : %d", buddy->flags); + weechat_log_printf (" color. . . . . : '%s'", buddy->color); + weechat_log_printf (" prev_buddy . . : 0x%lx", buddy->prev_buddy); + weechat_log_printf (" next_buddy . . : 0x%lx", buddy->next_buddy); +} diff --git a/src/plugins/jabber/jabber-buddy.h b/src/plugins/jabber/jabber-buddy.h new file mode 100644 index 000000000..fdc7261aa --- /dev/null +++ b/src/plugins/jabber/jabber-buddy.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_BUDDY_H +#define __WEECHAT_JABBER_BUDDY_H 1 + +#define JABBER_BUDDY_CHANOWNER 1 +#define JABBER_BUDDY_CHANADMIN 2 +#define JABBER_BUDDY_CHANADMIN2 4 +#define JABBER_BUDDY_OP 8 +#define JABBER_BUDDY_HALFOP 16 +#define JABBER_BUDDY_VOICE 32 +#define JABBER_BUDDY_AWAY 64 +#define JABBER_BUDDY_CHANUSER 128 +#define JABBER_BUDDY_SET_FLAG(buddy, set, flag) \ + if (set) \ + buddy->flags |= flag; \ + else \ + buddy->flags &= 0xFFFF - flag; + +#define JABBER_BUDDY_GROUP_OP "1|op" +#define JABBER_BUDDY_GROUP_HALFOP "2|halfop" +#define JABBER_BUDDY_GROUP_VOICE "3|voice" +#define JABBER_BUDDY_GROUP_CHANUSER "4|chanuser" +#define JABBER_BUDDY_GROUP_NORMAL "5|normal" + +struct t_jabber_server; +struct t_jabber_muc; + +struct t_jabber_buddy +{ + char *name; /* buddyname */ + char *host; /* full hostname */ + int flags; /* chanowner/chanadmin, op, halfop, */ + /* voice, away */ + const char *color; /* color for buddyname in chat window */ + struct t_jabber_buddy *prev_buddy; /* link to previous buddy in MUC */ + struct t_jabber_buddy *next_buddy; /* link to next buddy in MUC */ +}; + +extern int jabber_buddy_valid (struct t_jabber_server *server, + struct t_jabber_muc *muc, + struct t_jabber_buddy *buddy); +extern const char *jabber_buddy_find_color (struct t_jabber_buddy *buddy); +extern struct t_jabber_buddy *jabber_buddy_new (struct t_jabber_server *server, + struct t_jabber_muc *muc, + const char *buddy_name, + int is_chanowner, + int is_chanadmin, + int is_chanadmin2, + int is_op, + int is_halfop, + int has_voice, + int is_chanuser, + int is_away); +extern void jabber_buddy_change (struct t_jabber_server *server, + struct t_jabber_muc *muc, + struct t_jabber_buddy *buddy, + const char *new_buddy); +extern void jabber_buddy_set (struct t_jabber_server *server, + struct t_jabber_muc *muc, + struct t_jabber_buddy *buddy, int set, int flag); +extern void jabber_buddy_free (struct t_jabber_server *server, + struct t_jabber_muc *muc, + struct t_jabber_buddy *buddy); +extern void jabber_buddy_free_all (struct t_jabber_server *server, + struct t_jabber_muc *muc); +extern struct t_jabber_buddy *jabber_buddy_search (struct t_jabber_server *server, + struct t_jabber_muc *muc, + const char *buddyname); +extern void jabber_buddy_count (struct t_jabber_server *server, + struct t_jabber_muc *muc, int *total, + int *count_op, int *count_halfop, + int *count_voice, int *count_normal); +extern void jabber_buddy_set_away (struct t_jabber_server *server, + struct t_jabber_muc *muc, + struct t_jabber_buddy *buddy, int is_away); +extern char *jabber_buddy_as_prefix (struct t_jabber_buddy *buddy, + const char *buddyname, + const char *force_color); +extern int jabber_buddy_add_to_infolist (struct t_infolist *infolist, + struct t_jabber_buddy *buddy); +extern void jabber_buddy_print_log (struct t_jabber_buddy *buddy); + +#endif /* jabber-buddy.h */ diff --git a/src/plugins/jabber/jabber-buffer.c b/src/plugins/jabber/jabber-buffer.c new file mode 100644 index 000000000..a52200f9b --- /dev/null +++ b/src/plugins/jabber/jabber-buffer.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber-buffer.c: buffer functions for Jabber plugin */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-buffer.h" +#include "jabber-command.h" +#include "jabber-config.h" +#include "jabber-muc.h" +#include "jabber-server.h" + + +/* buffer for all servers (if using one buffer for all servers) */ +struct t_gui_buffer *jabber_buffer_servers = NULL; + + +/* + * jabber_buffer_get_server_muc: get Jabber server and MUC pointers + * with a buffer pointer + * (buffer may be a server or a MUC) + */ + +void +jabber_buffer_get_server_muc (struct t_gui_buffer *buffer, + struct t_jabber_server **server, + struct t_jabber_muc **muc) +{ + struct t_jabber_server *ptr_server; + struct t_jabber_muc *ptr_muc; + + if (server) + *server = NULL; + if (muc) + *muc = NULL; + + if (!buffer) + return; + + /* look for a server or MUC using this buffer */ + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (ptr_server->buffer == buffer) + { + if (server) + { + if (weechat_config_boolean (jabber_config_look_one_server_buffer)) + *server = jabber_current_server; + else + *server = ptr_server; + } + return; + } + + for (ptr_muc = ptr_server->mucs; ptr_muc; + ptr_muc = ptr_muc->next_muc) + { + if (ptr_muc->buffer == buffer) + { + if (server) + *server = ptr_server; + if (muc) + *muc = ptr_muc; + return; + } + } + } + + /* no server or MUC found */ +} + +/* + * jabber_buffer_build_name: build buffer name with a server and a MUC + */ + +char * +jabber_buffer_build_name (const char *server, const char *muc) +{ + static char buffer[128]; + + buffer[0] = '\0'; + + if (!server && !muc) + return buffer; + + if (server && muc) + snprintf (buffer, sizeof (buffer), "%s.%s", server, muc); + else + snprintf (buffer, sizeof (buffer), "%s", + (server) ? server : muc); + + return buffer; +} + +/* + * jabber_buffer_get_server_prefix: return prefix, with server name if server + * buffers are displayed in only one buffer + */ + +char * +jabber_buffer_get_server_prefix (struct t_jabber_server *server, + char *prefix_code) +{ + static char buf[256]; + const char *prefix; + + prefix = (prefix_code && prefix_code[0]) ? + weechat_prefix (prefix_code) : NULL; + + if (weechat_config_boolean (jabber_config_look_one_server_buffer) && server) + { + snprintf (buf, sizeof (buf), "%s%s[%s%s%s]%s ", + (prefix) ? prefix : "", + JABBER_COLOR_CHAT_DELIMITERS, + JABBER_COLOR_CHAT_SERVER, + server->name, + JABBER_COLOR_CHAT_DELIMITERS, + JABBER_COLOR_CHAT); + } + else + { + snprintf (buf, sizeof (buf), "%s", + (prefix) ? prefix : ""); + } + return buf; +} + +/* + * jabber_buffer_merge_servers: merge server buffers in one buffer + */ + +void +jabber_buffer_merge_servers () +{ + struct t_jabber_server *ptr_server; + struct t_gui_buffer *ptr_buffer; + int number, number_selected; + char charset_modifier[256]; + + jabber_buffer_servers = NULL; + jabber_current_server = NULL; + + /* choose server buffer with lower number (should be first created) */ + number_selected = -1; + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (ptr_server->buffer) + { + number = weechat_buffer_get_integer (ptr_server->buffer, "number"); + if ((number_selected == -1) || (number < number_selected)) + { + jabber_buffer_servers = ptr_server->buffer; + jabber_current_server = ptr_server; + number_selected = number; + } + } + } + + if (jabber_buffer_servers) + { + weechat_buffer_set (jabber_buffer_servers, + "name", JABBER_BUFFER_ALL_SERVERS_NAME); + weechat_buffer_set (jabber_buffer_servers, + "short_name", JABBER_BUFFER_ALL_SERVERS_NAME); + weechat_buffer_set (jabber_buffer_servers, "key_bind_meta-s", + "/command jabber /jabber switch"); + weechat_buffer_set (jabber_buffer_servers, + "localvar_set_server", JABBER_BUFFER_ALL_SERVERS_NAME); + weechat_buffer_set (jabber_buffer_servers, + "localvar_set_muc", JABBER_BUFFER_ALL_SERVERS_NAME); + snprintf (charset_modifier, sizeof (charset_modifier), + "jabber.%s", jabber_current_server->name); + weechat_buffer_set (jabber_buffer_servers, + "localvar_set_charset_modifier", + charset_modifier); + weechat_hook_signal_send ("logger_stop", + WEECHAT_HOOK_SIGNAL_POINTER, + jabber_buffer_servers); + weechat_hook_signal_send ("logger_start", + WEECHAT_HOOK_SIGNAL_POINTER, + jabber_buffer_servers); + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (ptr_server->buffer + && (ptr_server->buffer != jabber_buffer_servers)) + { + ptr_buffer = ptr_server->buffer; + ptr_server->buffer = jabber_buffer_servers; + weechat_buffer_close (ptr_buffer); + } + } + + jabber_server_set_buffer_title (jabber_current_server); + jabber_server_buffer_set_highlight_words (jabber_buffer_servers); + } +} + +/* + * jabber_buffer_split_server: split the server buffer into many buffers (one by server) + */ + +void +jabber_buffer_split_server () +{ + struct t_jabber_server *ptr_server; + char buffer_name[256], charset_modifier[256]; + + if (jabber_buffer_servers) + { + weechat_buffer_set (jabber_buffer_servers, "key_unbind_meta-s", ""); + } + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (ptr_server->buffer && (ptr_server != jabber_current_server)) + { + jabber_server_create_buffer (ptr_server, 0); + } + } + + if (jabber_current_server) + { + snprintf (buffer_name, sizeof (buffer_name), + "server.%s", jabber_current_server->name); + weechat_buffer_set (jabber_current_server->buffer, "name", buffer_name); + weechat_buffer_set (jabber_current_server->buffer, + "short_name", jabber_current_server->name); + weechat_buffer_set (jabber_current_server->buffer, + "localvar_set_server", jabber_current_server->name); + weechat_buffer_set (jabber_current_server->buffer, + "localvar_set_muc", jabber_current_server->name); + snprintf (charset_modifier, sizeof (charset_modifier), + "jabber.%s", jabber_current_server->name); + weechat_buffer_set (jabber_current_server->buffer, + "localvar_set_charset_modifier", + charset_modifier); + weechat_hook_signal_send ("logger_stop", + WEECHAT_HOOK_SIGNAL_POINTER, + jabber_current_server->buffer); + weechat_hook_signal_send ("logger_start", + WEECHAT_HOOK_SIGNAL_POINTER, + jabber_current_server->buffer); + } + + jabber_buffer_servers = NULL; + jabber_current_server = NULL; +} + +/* + * jabber_buffer_close_cb: callback called when a buffer is closed + */ + +int +jabber_buffer_close_cb (void *data, struct t_gui_buffer *buffer) +{ + JABBER_GET_SERVER_MUC(buffer); + + /* make C compiler happy */ + (void) data; + + if (ptr_muc) + { + /* send PART for channel if its buffer is closed */ + //if ((ptr_channel->type == JABBER_CHANNEL_TYPE_CHANNEL) + // && (ptr_channel->nicks)) + //{ + // jabber_command_part_channel (ptr_server, ptr_channel->name, NULL); + //} + jabber_muc_free (ptr_server, ptr_muc); + } + else + { + if (ptr_server) + { + /* send PART on all channels for server, then disconnect from server */ + //ptr_channel = ptr_server->channels; + //while (ptr_channel) + //{ + // next_channel = ptr_channel->next_channel; + // weechat_buffer_close (ptr_channel->buffer); + // ptr_channel = next_channel; + //} + jabber_server_disconnect (ptr_server, 0); + ptr_server->buffer = NULL; + } + } + + if (jabber_buffer_servers == buffer) + jabber_buffer_servers = NULL; + if (ptr_server && (jabber_current_server == ptr_server)) + jabber_current_server = NULL; + + return WEECHAT_RC_OK; +} diff --git a/src/plugins/jabber/jabber-buffer.h b/src/plugins/jabber/jabber-buffer.h new file mode 100644 index 000000000..032d8afe8 --- /dev/null +++ b/src/plugins/jabber/jabber-buffer.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_BUFFER_H +#define __WEECHAT_JABBER_BUFFER_H 1 + +#define JABBER_BUFFER_ALL_SERVERS_NAME "servers" + +struct t_gui_buffer; +struct t_jabber_server; +struct t_jabber_muc; + +extern struct t_gui_buffer *jabber_buffer_servers; + +extern void jabber_buffer_get_server_muc (struct t_gui_buffer *buffer, + struct t_jabber_server **server, + struct t_jabber_muc **muc); +extern char *jabber_buffer_build_name (const char *server, const char *muc); +extern char *jabber_buffer_get_server_prefix (struct t_jabber_server *server, + char *prefix_code); +extern void jabber_buffer_merge_servers (); +extern void jabber_buffer_split_server (); +extern int jabber_buffer_close_cb (void *data, struct t_gui_buffer *buffer); + +#endif /* jabber-buffer.h */ diff --git a/src/plugins/jabber/jabber-command.c b/src/plugins/jabber/jabber-command.c new file mode 100644 index 000000000..900e8e71d --- /dev/null +++ b/src/plugins/jabber/jabber-command.c @@ -0,0 +1,847 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber-command.c: Jabber commands */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <sys/time.h> +#include <time.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-command.h" +#include "jabber-buddy.h" +#include "jabber-buffer.h" +#include "jabber-config.h" +#include "jabber-input.h" +#include "jabber-muc.h" +#include "jabber-server.h" +#include "jabber-display.h" +#include "jabber-xmpp.h" + + +/* + * jabber_command_quit_server: send QUIT to a server + */ + +void +jabber_command_quit_server (struct t_jabber_server *server, + const char *arguments) +{ + if (!server) + return; + + (void) arguments; +} + +/* + * jabber_command_jabber: test + */ + +int +jabber_command_jabber (void *data, struct t_gui_buffer *buffer, int argc, + char **argv, char **argv_eol) +{ + int i, detailed_list, one_server_found; + struct t_jabber_server *ptr_server2, *server_found, *new_server; + char *server_name; + + JABBER_GET_SERVER_MUC(buffer); + + /* make C compiler happy */ + (void) data; + (void) buffer; + (void) argv_eol; + + if ((argc == 1) + || (weechat_strcasecmp (argv[1], "list") == 0) + || (weechat_strcasecmp (argv[1], "listfull") == 0)) + { + /* list servers */ + server_name = NULL; + detailed_list = 0; + for (i = 1; i < argc; i++) + { + if (weechat_strcasecmp (argv[i], "list") == 0) + continue; + if (weechat_strcasecmp (argv[i], "listfull") == 0) + { + detailed_list = 1; + continue; + } + if (!server_name) + server_name = argv[i]; + } + if (!server_name) + { + if (jabber_servers) + { + weechat_printf (NULL, ""); + weechat_printf (NULL, _("All servers:")); + for (ptr_server2 = jabber_servers; ptr_server2; + ptr_server2 = ptr_server2->next_server) + { + jabber_display_server (ptr_server2, detailed_list); + } + } + else + weechat_printf (NULL, _("No server")); + } + else + { + one_server_found = 0; + for (ptr_server2 = jabber_servers; ptr_server2; + ptr_server2 = ptr_server2->next_server) + { + if (weechat_strcasestr (ptr_server2->name, server_name)) + { + if (!one_server_found) + { + weechat_printf (NULL, ""); + weechat_printf (NULL, + _("Servers with \"%s\":"), + server_name); + } + one_server_found = 1; + jabber_display_server (ptr_server2, detailed_list); + } + } + if (!one_server_found) + weechat_printf (NULL, + _("No server found with \"%s\""), + server_name); + } + + return WEECHAT_RC_OK; + } + + if (weechat_strcasecmp (argv[1], "add") == 0) + { + if (argc < 6) + { + JABBER_COMMAND_TOO_FEW_ARGUMENTS(NULL, "server add"); + } + if (jabber_server_search (argv[2])) + { + weechat_printf (NULL, + _("%s%s: server \"%s\" already exists, " + "can't create it!"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + argv[2]); + return WEECHAT_RC_ERROR; + } + + new_server = jabber_server_alloc (argv[2]); + if (!new_server) + { + weechat_printf (NULL, + _("%s%s: unable to create server"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME); + return WEECHAT_RC_ERROR; + } + + weechat_config_option_set (new_server->options[JABBER_SERVER_OPTION_USERNAME], + argv[3], 1); + weechat_config_option_set (new_server->options[JABBER_SERVER_OPTION_SERVER], + argv[4], 1); + weechat_config_option_set (new_server->options[JABBER_SERVER_OPTION_PASSWORD], + argv[5], 1); + + /* parse arguments */ + for (i = 6; i < argc; i++) + { + if (argv[i][0] == '-') + { + if (weechat_strcasecmp (argv[i], "-auto") == 0) + { + weechat_config_option_set (new_server->options[JABBER_SERVER_OPTION_AUTOCONNECT], + "on", 1); + } + if (weechat_strcasecmp (argv[i], "-noauto") == 0) + { + weechat_config_option_set (new_server->options[JABBER_SERVER_OPTION_AUTOCONNECT], + "off", 1); + } + if (weechat_strcasecmp (argv[i], "-ipv6") == 0) + { + weechat_config_option_set (new_server->options[JABBER_SERVER_OPTION_IPV6], + "on", 1); + } + if (weechat_strcasecmp (argv[i], "-tls") == 0) + { + weechat_config_option_set (new_server->options[JABBER_SERVER_OPTION_TLS], + "on", 1); + } + if (weechat_strcasecmp (argv[i], "-sasl") == 0) + { + weechat_config_option_set (new_server->options[JABBER_SERVER_OPTION_SASL], + "on", 1); + } + } + } + + weechat_printf (NULL, + _("%s: server %s%s%s created"), + JABBER_PLUGIN_NAME, + JABBER_COLOR_CHAT_SERVER, + new_server->name, + JABBER_COLOR_CHAT); + + if (JABBER_SERVER_OPTION_BOOLEAN(new_server, JABBER_SERVER_OPTION_AUTOCONNECT)) + jabber_server_connect (new_server); + + return WEECHAT_RC_OK; + } + + if (weechat_strcasecmp (argv[1], "copy") == 0) + { + if (argc < 4) + { + JABBER_COMMAND_TOO_FEW_ARGUMENTS(NULL, "server copy"); + } + + /* look for server by name */ + server_found = jabber_server_search (argv[2]); + if (!server_found) + { + weechat_printf (NULL, + _("%s%s: server \"%s\" not found for " + "\"%s\" command"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + argv[2], "server copy"); + return WEECHAT_RC_ERROR; + } + + /* check if target name already exists */ + if (jabber_server_search (argv[3])) + { + weechat_printf (NULL, + _("%s%s: server \"%s\" already exists for " + "\"%s\" command"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + argv[3], "server copy"); + return WEECHAT_RC_ERROR; + } + + /* copy server */ + new_server = jabber_server_copy (server_found, argv[3]); + if (new_server) + { + weechat_printf (NULL, + _("%s: server %s%s%s has been copied to " + "%s%s"), + JABBER_PLUGIN_NAME, + JABBER_COLOR_CHAT_SERVER, + argv[2], + JABBER_COLOR_CHAT, + JABBER_COLOR_CHAT_SERVER, + argv[3]); + return WEECHAT_RC_OK; + } + + return WEECHAT_RC_ERROR; + } + + if (weechat_strcasecmp (argv[1], "rename") == 0) + { + if (argc < 4) + { + JABBER_COMMAND_TOO_FEW_ARGUMENTS(NULL, "server rename"); + } + + /* look for server by name */ + server_found = jabber_server_search (argv[2]); + if (!server_found) + { + weechat_printf (NULL, + _("%s%s: server \"%s\" not found for " + "\"%s\" command"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + argv[2], "server rename"); + return WEECHAT_RC_ERROR; + } + + /* check if target name already exists */ + if (jabber_server_search (argv[3])) + { + weechat_printf (NULL, + _("%s%s: server \"%s\" already exists for " + "\"%s\" command"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + argv[3], "server rename"); + return WEECHAT_RC_ERROR; + } + + /* rename server */ + if (jabber_server_rename (server_found, argv[3])) + { + weechat_printf (NULL, + _("%s: server %s%s%s has been renamed to " + "%s%s"), + JABBER_PLUGIN_NAME, + JABBER_COLOR_CHAT_SERVER, + argv[2], + JABBER_COLOR_CHAT, + JABBER_COLOR_CHAT_SERVER, + argv[3]); + return WEECHAT_RC_OK; + } + + return WEECHAT_RC_ERROR; + } + + if (weechat_strcasecmp (argv[1], "keep") == 0) + { + if (argc < 3) + { + JABBER_COMMAND_TOO_FEW_ARGUMENTS(NULL, "server keep"); + } + + /* look for server by name */ + server_found = jabber_server_search (argv[2]); + if (!server_found) + { + weechat_printf (NULL, + _("%s%s: server \"%s\" not found for " + "\"%s\" command"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + argv[2], "server keep"); + return WEECHAT_RC_ERROR; + } + + /* check that is it temporary server */ + if (!server_found->temp_server) + { + weechat_printf (NULL, + _("%s%s: server \"%s\" is not a temporary server"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + argv[2], "server keep"); + return WEECHAT_RC_ERROR; + } + + /* remove temporary flag on server */ + server_found->temp_server = 0; + + weechat_printf (NULL, + _("%s: server %s%s%s is not temporary any more"), + JABBER_PLUGIN_NAME, + JABBER_COLOR_CHAT_SERVER, + argv[2], + JABBER_COLOR_CHAT); + + return WEECHAT_RC_OK; + } + + if (weechat_strcasecmp (argv[1], "del") == 0) + { + if (argc < 3) + { + JABBER_COMMAND_TOO_FEW_ARGUMENTS(NULL, "server del"); + } + + /* look for server by name */ + server_found = jabber_server_search (argv[2]); + if (!server_found) + { + weechat_printf (NULL, + _("%s%s: server \"%s\" not found for " + "\"%s\" command"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + argv[2], "server del"); + return WEECHAT_RC_ERROR; + } + if (server_found->is_connected) + { + weechat_printf (NULL, + _("%s%s: you can not delete server \"%s\" " + "because you are connected to. " + "Try \"/disconnect %s\" before."), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + argv[2], argv[2]); + return WEECHAT_RC_ERROR; + } + + server_name = strdup (server_found->name); + jabber_server_free (server_found); + weechat_printf (NULL, + _("%s: Server %s%s%s has been deleted"), + JABBER_PLUGIN_NAME, + JABBER_COLOR_CHAT_SERVER, + (server_name) ? server_name : "???", + JABBER_COLOR_CHAT); + if (server_name) + free (server_name); + + return WEECHAT_RC_OK; + } + + if (weechat_strcasecmp (argv[1], "switch") == 0) + { + if (weechat_config_boolean (jabber_config_look_one_server_buffer)) + { + if (jabber_current_server) + { + ptr_server2 = jabber_current_server->next_server; + if (!ptr_server2) + ptr_server2 = jabber_servers; + while (ptr_server2 != jabber_current_server) + { + if (ptr_server2->buffer) + { + jabber_current_server = ptr_server2; + break; + } + ptr_server2 = ptr_server2->next_server; + if (!ptr_server2) + ptr_server2 = jabber_servers; + } + } + else + { + for (ptr_server2 = jabber_servers; ptr_server2; + ptr_server2 = ptr_server2->next_server) + { + if (ptr_server2->buffer) + { + jabber_current_server = ptr_server2; + break; + } + } + } + jabber_server_set_current_server (jabber_current_server); + } + return WEECHAT_RC_OK; + } + + weechat_printf (NULL, + _("%s%s: unknown option for \"%s\" command"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, "server"); + + return WEECHAT_RC_ERROR; +} + +/* + * jabber_command_jchat: chat with a buddy + */ + +int +jabber_command_jchat (void *data, struct t_gui_buffer *buffer, int argc, + char **argv, char **argv_eol) +{ + JABBER_GET_SERVER_MUC(buffer); + if (!ptr_server || !ptr_server->is_connected || !ptr_server->iks_authorized) + return WEECHAT_RC_ERROR; + + /* make C compiler happy */ + (void) data; + (void) argv; + + if (argc > 1) + { + /* create private window if not already opened */ + ptr_muc = jabber_muc_search (ptr_server, argv[1]); + if (!ptr_muc) + { + ptr_muc = jabber_muc_new (ptr_server, + JABBER_MUC_TYPE_PRIVATE, + argv[1], 1); + if (!ptr_muc) + { + weechat_printf (ptr_server->buffer, + _("%s%s: cannot create new private " + "buffer \"%s\""), + jabber_buffer_get_server_prefix (ptr_server, "error"), + JABBER_PLUGIN_NAME, argv[1]); + return WEECHAT_RC_ERROR; + } + } + weechat_buffer_set (ptr_muc->buffer, "display", "1"); + + /* display text if given */ + if (argv_eol[2]) + { + jabber_xmpp_send_chat_message (ptr_server, ptr_muc, argv_eol[2]); + jabber_input_user_message_display (ptr_muc->buffer, argv_eol[2]); + } + } + else + { + JABBER_COMMAND_TOO_FEW_ARGUMENTS(ptr_server->buffer, "chat"); + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_command_jconnect_one_server: connect to one server + * return 0 if error, 1 if ok + */ + +int +jabber_command_jconnect_one_server (struct t_jabber_server *server, int no_join) +{ + if (!server) + return 0; + + if (server->is_connected) + { + weechat_printf (NULL, + _("%s%s: already connected to server " + "\"%s\"!"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + server->name); + return 0; + } + if (server->hook_connect) + { + weechat_printf (NULL, + _("%s%s: currently connecting to server " + "\"%s\"!"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + server->name); + return 0; + } + server->disable_autojoin = no_join; + if (jabber_server_connect (server)) + { + server->reconnect_start = 0; + server->reconnect_join = (server->mucs) ? 1 : 0; + } + + /* connect ok */ + return 1; +} + +/* + * jabber_command_jconnect: connect to server(s) + */ + +int +jabber_command_jconnect (void *data, struct t_gui_buffer *buffer, int argc, + char **argv, char **argv_eol) +{ + int i, nb_connect, connect_ok, all_servers, no_join, port, ipv6, tls, sasl; + char *name, *error; + long number; + + JABBER_GET_SERVER(buffer); + + /* make C compiler happy */ + (void) data; + (void) argv_eol; + + nb_connect = 0; + connect_ok = 1; + port = JABBER_SERVER_DEFAULT_PORT; + ipv6 = 0; + tls = 0; + sasl = 0; + + all_servers = 0; + no_join = 0; + for (i = 1; i < argc; i++) + { + if (weechat_strcasecmp (argv[i], "-all") == 0) + all_servers = 1; + if (weechat_strcasecmp (argv[i], "-nojoin") == 0) + no_join = 1; + if (weechat_strcasecmp (argv[i], "-ipv6") == 0) + ipv6 = 1; + if (weechat_strcasecmp (argv[i], "-tls") == 0) + tls = 1; + if (weechat_strcasecmp (argv[i], "-sasl") == 0) + sasl = 1; + if (weechat_strcasecmp (argv[i], "-port") == 0) + { + if (i == (argc - 1)) + { + weechat_printf (NULL, + _("%s%s: missing argument for \"%s\" " + "option"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + "-port"); + return WEECHAT_RC_ERROR; + } + error = NULL; + number = strtol (argv[++i], &error, 10); + if (error && !error[0]) + port = number; + } + } + + if (all_servers) + { + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + nb_connect++; + if (!ptr_server->is_connected && (!ptr_server->hook_connect)) + { + if (!jabber_command_jconnect_one_server (ptr_server, no_join)) + connect_ok = 0; + } + } + } + else + { + for (i = 1; i < argc; i++) + { + if (argv[i][0] != '-') + { + nb_connect++; + ptr_server = jabber_server_search (argv[i]); + if (ptr_server) + { + if (!jabber_command_jconnect_one_server (ptr_server, no_join)) + connect_ok = 0; + } + else + { + name = jabber_server_get_name_without_port (argv[i]); + ptr_server = jabber_server_alloc ((name) ? name : argv[i]); + if (name) + free (name); + if (ptr_server) + { + ptr_server->temp_server = 1; + weechat_config_option_set (ptr_server->options[JABBER_SERVER_OPTION_SERVER], + argv[i], 1); + weechat_printf (NULL, + _("%s: server %s%s%s created (temporary server, NOT SAVED!)"), + JABBER_PLUGIN_NAME, + JABBER_COLOR_CHAT_SERVER, + ptr_server->name, + JABBER_COLOR_CHAT); + if (!jabber_command_jconnect_one_server (ptr_server, 0)) + connect_ok = 0; + } + else + { + weechat_printf (NULL, + _("%s%s: unable to create server " + "\"%s\""), + weechat_prefix ("error"), + JABBER_PLUGIN_NAME, argv[i]); + } + } + } + else + { + if (weechat_strcasecmp (argv[i], "-port") == 0) + i++; + } + } + } + + if (nb_connect == 0) + connect_ok = jabber_command_jconnect_one_server (ptr_server, no_join); + + if (!connect_ok) + return WEECHAT_RC_ERROR; + + return WEECHAT_RC_OK; +} + +/* + * jabber_command_jdisconnect_one_server: disconnect from a server + * return 0 if error, 1 if ok + */ + +int +jabber_command_jdisconnect_one_server (struct t_jabber_server *server) +{ + if (!server) + return 0; + + if ((!server->is_connected) && (!server->hook_connect) + && (server->reconnect_start == 0)) + { + weechat_printf (server->buffer, + _("%s%s: not connected to server \"%s\"!"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME, server->name); + return 0; + } + if (server->reconnect_start > 0) + { + weechat_printf (server->buffer, + _("%s%s: auto-reconnection is cancelled"), + jabber_buffer_get_server_prefix (server, NULL), + JABBER_PLUGIN_NAME); + } + jabber_command_quit_server (server, NULL); + jabber_server_disconnect (server, 0); + + /* disconnect ok */ + return 1; +} + +/* + * jabber_command_jdisconnect: disconnect from server(s) + */ + +int +jabber_command_jdisconnect (void *data, struct t_gui_buffer *buffer, int argc, + char **argv, char **argv_eol) +{ + int i, disconnect_ok; + + JABBER_GET_SERVER(buffer); + + /* make C compiler happy */ + (void) data; + (void) argv_eol; + + if (argc < 2) + disconnect_ok = jabber_command_jdisconnect_one_server (ptr_server); + else + { + disconnect_ok = 1; + + if (weechat_strcasecmp (argv[1], "-all") == 0) + { + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if ((ptr_server->is_connected) || (ptr_server->hook_connect) + || (ptr_server->reconnect_start != 0)) + { + if (!jabber_command_jdisconnect_one_server (ptr_server)) + disconnect_ok = 0; + } + } + } + else + { + for (i = 1; i < argc; i++) + { + ptr_server = jabber_server_search (argv[i]); + if (ptr_server) + { + if (!jabber_command_jdisconnect_one_server (ptr_server)) + disconnect_ok = 0; + } + else + { + weechat_printf (NULL, + _("%s%s: server \"%s\" not found"), + weechat_prefix ("error"), + JABBER_PLUGIN_NAME, argv[i]); + disconnect_ok = 0; + } + } + } + } + + if (!disconnect_ok) + return WEECHAT_RC_ERROR; + + return WEECHAT_RC_OK; +} + +/* + * jabber_command_init: init Jabber commands (create hooks) + */ + +void +jabber_command_init () +{ + weechat_hook_command ("jabber", + N_("list, add or remove Jabber servers"), + N_("[list [servername]] | [listfull [servername]] | " + "[add servername username hostname[/port] password " + "[-auto | -noauto] [-ipv6] [-tls] [-sasl]] | " + "[copy servername newservername] | " + "[rename servername newservername] | " + "[keep servername] | [del servername] | " + "[switch]"), + N_(" list: list servers (no parameter implies " + "this list)\n" + " listfull: list servers with detailed info for " + "each server\n" + " add: create a new server\n" + "servername: server name, for internal and " + "display use\n" + " username: username to use on server\n" + " hostname: name or IP address of server, with " + "optional port (default: 5222)\n" + " password: password for username on server\n" + " auto: automatically connect to server " + "when WeeChat starts\n" + " noauto: do not connect to server when " + "WeeChat starts (default)\n" + " ipv6: use IPv6 protocol\n" + " tls: use TLS cryptographic protocol\n" + " sasl: use SASL for authentication\n" + " copy: duplicate a server\n" + " rename: rename a server\n" + " keep: keep server in config file (for " + "temporary servers only)\n" + " del: delete a server\n" + " switch: switch active server (when one " + "buffer is used for all servers, default key: " + "alt-s on server buffer)\n\n" + "Examples:\n" + " /jabber listfull\n" + " /jabber add jabberfr user jabber.fr/5222 " + "password -tls\n" + " /jabber copy jabberfr jabberfr2\n" + " /jabber rename jabberfr jabbfr\n" + " /jabber del jabberfr\n" + " /jabber switch"), + "add|copy|rename|keep|del|list|listfull|switch " + "%(jabber_servers) %(jabber_servers)", + &jabber_command_jabber, NULL); + weechat_hook_command ("jchat", + N_("chat with a buddy"), + N_("buddy [text]"), + N_("buddy: buddy name for chat\n" + " text: text to send"), + "%n %-", &jabber_command_jchat, NULL); + weechat_hook_command ("jconnect", + N_("connect to Jabber server(s)"), + N_("[-all [-nojoin] | servername [servername ...] " + "[-nojoin] | hostname [-port port] [-ipv6] " + "[-tls] [-sasl]]"), + N_(" -all: connect to all servers\n" + "servername: internal server name to connect\n" + " -nojoin: do not join any MUC (even if " + "autojoin is enabled on server)\n" + " hostname: hostname to connect\n" + " port: port for server (integer, default " + "is 6667)\n" + " ipv6: use IPv6 protocol\n" + " tls: use TLS cryptographic protocol\n" + " saal: use SASL for authentication"), + "%(jabber_servers)|-all|-nojoin|%*", + &jabber_command_jconnect, NULL); + weechat_hook_command ("jdisconnect", + N_("disconnect from Jabber server(s)"), + N_("[-all | servername [servername ...]]"), + N_(" -all: disconnect from all servers\n" + "servername: server name to disconnect"), + "%(jabber_servers)|-all", + &jabber_command_jdisconnect, NULL); +} diff --git a/src/plugins/jabber/jabber-command.h b/src/plugins/jabber/jabber-command.h new file mode 100644 index 000000000..5a2c15138 --- /dev/null +++ b/src/plugins/jabber/jabber-command.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_COMMAND_H +#define __WEECHAT_JABBER_COMMAND_H 1 + +struct t_jabber_server; + +#define JABBER_COMMAND_TOO_FEW_ARGUMENTS(__buffer, __command) \ + weechat_printf (__buffer, \ + _("%s%s: too few arguments for \"%s\" command"), \ + jabber_buffer_get_server_prefix (ptr_server, "error"), \ + JABBER_PLUGIN_NAME, \ + __command); \ + return WEECHAT_RC_ERROR; + +extern void jabber_command_quit_server (struct t_jabber_server *server, + const char *arguments); +extern void jabber_command_init (); + +#endif /* jabber-command.h */ diff --git a/src/plugins/jabber/jabber-completion.c b/src/plugins/jabber/jabber-completion.c new file mode 100644 index 000000000..e08f665b1 --- /dev/null +++ b/src/plugins/jabber/jabber-completion.c @@ -0,0 +1,448 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber-completion.c: completion for Jabber commands */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-buddy.h" +#include "jabber-buffer.h" +#include "jabber-completion.h" +#include "jabber-config.h" +#include "jabber-muc.h" +#include "jabber-server.h" + + +/* + * jabber_completion_server_cb: callback for completion with current server + */ + +int +jabber_completion_server_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + JABBER_GET_SERVER(buffer); + + /* make C compiler happy */ + (void) data; + (void) completion_item; + + if (ptr_server) + { + weechat_hook_completion_list_add (completion, ptr_server->name, + 0, WEECHAT_LIST_POS_SORT); + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_completion_server_local_name_cb: callback for completion with local + * name on server + */ + +int +jabber_completion_server_local_name_cb (void *data, + const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + const char *local_name; + + JABBER_GET_SERVER(buffer); + + /* make C compiler happy */ + (void) data; + (void) completion_item; + + if (ptr_server) + { + local_name = jabber_server_get_local_name (ptr_server); + if (local_name && local_name[0]) + { + weechat_hook_completion_list_add (completion, local_name, + 1, WEECHAT_LIST_POS_SORT); + } + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_completion_server_buddies_cb: callback for completion with buddies + * of current server + */ + +int +jabber_completion_server_buddies_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + struct t_jabber_muc *ptr_muc2; + struct t_jabber_buddy *ptr_buddy; + const char *local_name; + + JABBER_GET_SERVER_MUC(buffer); + + /* make C compiler happy */ + (void) data; + (void) completion_item; + + if (ptr_server) + { + for (ptr_muc2 = ptr_server->mucs; ptr_muc2; + ptr_muc2 = ptr_muc2->next_muc) + { + if (ptr_muc2->type == JABBER_MUC_TYPE_MUC) + { + for (ptr_buddy = ptr_muc2->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + weechat_hook_completion_list_add (completion, + ptr_buddy->name, + 1, WEECHAT_LIST_POS_SORT); + } + } + } + + local_name = jabber_server_get_local_name (ptr_server); + + if (local_name && local_name[0]) + { + /* add local name at the end */ + weechat_hook_completion_list_add (completion, local_name, + 1, WEECHAT_LIST_POS_END); + } + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_completion_servers_cb: callback for completion with servers + */ + +int +jabber_completion_servers_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + struct t_jabber_server *ptr_server; + + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + weechat_hook_completion_list_add (completion, ptr_server->name, + 0, WEECHAT_LIST_POS_SORT); + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_completion_muc_cb: callback for completion with current MUC + */ + +int +jabber_completion_muc_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + JABBER_GET_SERVER_MUC(buffer); + + /* make C compiler happy */ + (void) data; + (void) completion_item; + + if (ptr_muc) + { + weechat_hook_completion_list_add (completion, ptr_muc->name, + 0, WEECHAT_LIST_POS_SORT); + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_completion_muc_buddies_cb: callback for completion with buddies + * of current MUC + */ + +int +jabber_completion_muc_buddies_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + struct t_jabber_buddy *ptr_buddy; + const char *buddy, *local_name; + int list_size, i, j; + + JABBER_GET_SERVER_MUC(buffer); + + /* make C compiler happy */ + (void) data; + (void) completion_item; + + if (ptr_muc) + { + switch (ptr_muc->type) + { + case JABBER_MUC_TYPE_MUC: + for (ptr_buddy = ptr_muc->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + weechat_hook_completion_list_add (completion, + ptr_buddy->name, + 1, + WEECHAT_LIST_POS_SORT); + } + /* add buddies speaking recently on this MUC */ + if (weechat_config_boolean (jabber_config_look_nick_completion_smart)) + { + /* 0 => buddy speaking ; 1 => buddy speaking to me + (with highlight) */ + for (i = 0; i < 2; i++) + { + if (ptr_muc->buddies_speaking[i]) + { + list_size = weechat_list_size (ptr_muc->buddies_speaking[i]); + for (j = 0; j < list_size; j++) + { + buddy = weechat_list_string (weechat_list_get (ptr_muc->buddies_speaking[i], j)); + if (buddy && jabber_buddy_search (NULL, ptr_muc, buddy)) + { + weechat_hook_completion_list_add (completion, + buddy, + 1, + WEECHAT_LIST_POS_BEGINNING); + } + } + } + } + } + /* add local name at the end */ + local_name = jabber_server_get_local_name (ptr_server); + if (local_name && local_name[0]) + { + weechat_hook_completion_list_add (completion, + local_name, + 1, + WEECHAT_LIST_POS_END); + } + break; + case JABBER_MUC_TYPE_PRIVATE: + weechat_hook_completion_list_add (completion, + ptr_muc->name, + 0, + WEECHAT_LIST_POS_SORT); + break; + } + ptr_muc->nick_completion_reset = 0; + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_completion_muc_buddies_hosts_cb: callback for completion with buddies + * and hosts of current MUC + */ + +int +jabber_completion_muc_buddies_hosts_cb (void *data, + const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + struct t_jabber_buddy *ptr_buddy; + char *buf; + int length; + + JABBER_GET_SERVER_MUC(buffer); + + /* make C compiler happy */ + (void) data; + (void) completion_item; + + if (ptr_muc) + { + switch (ptr_muc->type) + { + case JABBER_MUC_TYPE_MUC: + for (ptr_buddy = ptr_muc->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + weechat_hook_completion_list_add (completion, + ptr_buddy->name, + 1, + WEECHAT_LIST_POS_SORT); + if (ptr_buddy->host) + { + length = strlen (ptr_buddy->name) + 1 + + strlen (ptr_buddy->host) + 1; + buf = malloc (length); + if (buf) + { + snprintf (buf, length, "%s!%s", + ptr_buddy->name, ptr_buddy->host); + weechat_hook_completion_list_add (completion, + buf, + 0, + WEECHAT_LIST_POS_SORT); + free (buf); + } + } + } + break; + case JABBER_MUC_TYPE_PRIVATE: + weechat_hook_completion_list_add (completion, + ptr_muc->name, + 0, + WEECHAT_LIST_POS_SORT); + } + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_completion_muc_topic_cb: callback for completion with topic of + * current MUC + */ + +int +jabber_completion_muc_topic_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + JABBER_GET_SERVER_MUC(buffer); + + /* make C compiler happy */ + (void) data; + (void) completion_item; + + if (ptr_muc && ptr_muc->topic && ptr_muc->topic[0]) + { + weechat_hook_completion_list_add (completion, + ptr_muc->topic, + 0, + WEECHAT_LIST_POS_SORT); + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_completion_mucs_cb: callback for completion with MUCs + */ + +int +jabber_completion_mucs_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + (void) completion; + + struct t_jabber_server *ptr_server; + struct t_jabber_muc *ptr_muc; + + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + for (ptr_muc = ptr_server->mucs; ptr_muc; ptr_muc = ptr_muc->next_muc) + { + weechat_hook_completion_list_add (completion, + ptr_muc->name, + 0, + WEECHAT_LIST_POS_SORT); + } + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_completion_msg_part_cb: callback for completion with default part + * message + */ + +int +jabber_completion_msg_part_cb (void *data, const char *completion_item, + struct t_gui_buffer *buffer, + struct t_gui_completion *completion) +{ + /* make C compiler happy */ + (void) data; + (void) completion_item; + (void) buffer; + + if (weechat_config_string (jabber_config_network_default_msg_part) + && weechat_config_string (jabber_config_network_default_msg_part)[0]) + { + weechat_hook_completion_list_add (completion, + weechat_config_string (jabber_config_network_default_msg_part), + 0, WEECHAT_LIST_POS_SORT); + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_completion_init: init completion for Jabber plugin + */ + +void +jabber_completion_init () +{ + weechat_hook_completion ("jabber_server", + &jabber_completion_server_cb, NULL); + weechat_hook_completion ("jabber_server_local_name", + &jabber_completion_server_local_name_cb, NULL); + weechat_hook_completion ("jabber_server_buddies", + &jabber_completion_server_buddies_cb, NULL); + weechat_hook_completion ("jabber_servers", + &jabber_completion_servers_cb, NULL); + weechat_hook_completion ("jabber_muc", + &jabber_completion_muc_cb, NULL); + weechat_hook_completion ("buddy", + &jabber_completion_muc_buddies_cb, NULL); + weechat_hook_completion ("jabber_muc_buddies_hosts", + &jabber_completion_muc_buddies_hosts_cb, NULL); + weechat_hook_completion ("jabber_muc_topic", + &jabber_completion_muc_topic_cb, NULL); + weechat_hook_completion ("jabber_mucs", + &jabber_completion_mucs_cb, NULL); + weechat_hook_completion ("jabber_msg_part", + &jabber_completion_msg_part_cb, NULL); +} diff --git a/src/plugins/jabber/jabber-completion.h b/src/plugins/jabber/jabber-completion.h new file mode 100644 index 000000000..8f0d187b5 --- /dev/null +++ b/src/plugins/jabber/jabber-completion.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_COMPLETION_H +#define __WEECHAT_JABBER_COMPLETION_H 1 + +extern void jabber_completion_init (); + +#endif /* jabber-completion.h */ diff --git a/src/plugins/jabber/jabber-config.c b/src/plugins/jabber/jabber-config.c new file mode 100644 index 000000000..9ea5dc862 --- /dev/null +++ b/src/plugins/jabber/jabber-config.c @@ -0,0 +1,990 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber-config.c: Jabber configuration options */ + + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <limits.h> +#include <pwd.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-config.h" +#include "jabber-buffer.h" +#include "jabber-buddy.h" +#include "jabber-server.h" +#include "jabber-muc.h" + + +struct t_config_file *jabber_config_file = NULL; +struct t_config_section *jabber_config_section_server_default = NULL; +struct t_config_section *jabber_config_section_server = NULL; + +/* Jabber config, look section */ + +struct t_config_option *jabber_config_look_color_nicks_in_server_messages; +struct t_config_option *jabber_config_look_one_server_buffer; +struct t_config_option *jabber_config_look_open_near_server; +struct t_config_option *jabber_config_look_nick_prefix; +struct t_config_option *jabber_config_look_nick_suffix; +struct t_config_option *jabber_config_look_nick_completion_smart; +struct t_config_option *jabber_config_look_display_away; +struct t_config_option *jabber_config_look_display_muc_modes; +struct t_config_option *jabber_config_look_hide_nickserv_pwd; +struct t_config_option *jabber_config_look_highlight_tags; +struct t_config_option *jabber_config_look_show_away_once; +struct t_config_option *jabber_config_look_smart_filter; +struct t_config_option *jabber_config_look_smart_filter_delay; +struct t_config_option *jabber_config_look_notice_as_pv; + +/* Jabber config, color section */ + +struct t_config_option *jabber_config_color_message_join; +struct t_config_option *jabber_config_color_message_quit; +struct t_config_option *jabber_config_color_input_nick; + +/* Jabber config, network section */ + +struct t_config_option *jabber_config_network_default_msg_part; +struct t_config_option *jabber_config_network_default_msg_quit; +struct t_config_option *jabber_config_network_lag_check; +struct t_config_option *jabber_config_network_lag_min_show; +struct t_config_option *jabber_config_network_lag_disconnect; +struct t_config_option *jabber_config_network_anti_flood; +struct t_config_option *jabber_config_network_colors_receive; +struct t_config_option *jabber_config_network_colors_send; + +/* Jabber config, server section */ + +struct t_config_option *jabber_config_server_default[JABBER_SERVER_NUM_OPTIONS]; + +struct t_hook *hook_config_color_nicks_number = NULL; + +int jabber_config_write_temp_servers = 0; + + +struct t_jabber_server * +jabber_config_get_server_from_option_name (const char *name) +{ + struct t_jabber_server *ptr_server; + char *pos_option, *server_name; + + ptr_server = NULL; + + if (name) + { + pos_option = strrchr (name, '.'); + if (pos_option) + { + server_name = weechat_strndup (name, pos_option - name); + if (server_name) + { + ptr_server = jabber_server_search (server_name); + free (server_name); + } + } + } + + return ptr_server; +} + +/* + * jabber_config_change_look_color_nicks_number: called when the + * "weechat.look.color_nicks_number" + * option is changed + */ + +int +jabber_config_change_look_color_nicks_number (void *data, const char *option, + const char *value) +{ + struct t_jabber_server *ptr_server; + struct t_jabber_muc *ptr_muc; + struct t_jabber_buddy *ptr_buddy; + + /* make C compiler happy */ + (void) data; + (void) option; + (void) value; + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + /* buddies in roster */ + for (ptr_buddy = ptr_server->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + ptr_buddy->color = jabber_buddy_find_color (ptr_buddy); + } + /* buddies in MUCs */ + for (ptr_muc = ptr_server->mucs; ptr_muc; ptr_muc = ptr_muc->next_muc) + { + for (ptr_buddy = ptr_muc->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + ptr_buddy->color = jabber_buddy_find_color (ptr_buddy); + } + } + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_config_change_look_one_server_buffer: called when the "one server buffer" + * option is changed + */ + +void +jabber_config_change_look_one_server_buffer (void *data, + struct t_config_option *option) +{ + /* make C compiler happy */ + (void) data; + (void) option; + + if (weechat_config_boolean (jabber_config_look_one_server_buffer)) + jabber_buffer_merge_servers (); + else + jabber_buffer_split_server (); +} + +/* + * jabber_config_change_look_display_muc_modes: called when the "display + * MUC modes" option is changed + */ + +void +jabber_config_change_look_display_muc_modes (void *data, + struct t_config_option *option) +{ + /* make C compiler happy */ + (void) data; + (void) option; + + weechat_bar_item_update ("buffer_name"); +} + +/* + * jabber_config_change_look_highlight_tags: called when the "highlight tags" + * option is changed + */ + +void +jabber_config_change_look_highlight_tags (void *data, + struct t_config_option *option) +{ + struct t_jabber_server *ptr_server; + struct t_jabber_muc *ptr_muc; + + /* make C compiler happy */ + (void) data; + (void) option; + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (ptr_server->buffer) + { + weechat_buffer_set (ptr_server->buffer, "highlight_tags", + weechat_config_string (jabber_config_look_highlight_tags)); + } + for (ptr_muc = ptr_server->mucs; ptr_muc; ptr_muc = ptr_muc->next_muc) + { + if (ptr_muc->buffer) + { + weechat_buffer_set (ptr_muc->buffer, "highlight_tags", + weechat_config_string (jabber_config_look_highlight_tags)); + } + } + } +} + +/* + * jabber_config_change_color_input_nick: called when the color of input nick + * ischanged + */ + +void +jabber_config_change_color_input_nick (void *data, + struct t_config_option *option) +{ + /* make C compiler happy */ + (void) data; + (void) option; + + weechat_bar_item_update ("input_prompt"); +} + +/* + * jabber_config_server_default_change_cb: callback called when a default server + * option is modified + */ + +void +jabber_config_server_default_change_cb (void *data, + struct t_config_option *option) +{ + int index_option; + struct t_jabber_server *ptr_server; + + index_option = jabber_server_search_option (data); + if (index_option >= 0) + { + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (weechat_config_option_is_null (ptr_server->options[index_option])) + { + switch (index_option) + { + case JABBER_SERVER_OPTION_SERVER: + jabber_server_set_server (ptr_server, + weechat_config_string (option)); + break; + } + } + } + } +} + +/* + * jabber_config_server_change_cb: callback called when a server option is + * modified + */ + +void +jabber_config_server_change_cb (void *data, struct t_config_option *option) +{ + int index_option; + char *name; + struct t_jabber_server *ptr_server; + + index_option = jabber_server_search_option (data); + if (index_option >= 0) + { + name = weechat_config_option_get_pointer (option, "name"); + ptr_server = jabber_config_get_server_from_option_name (name); + if (ptr_server) + { + switch (index_option) + { + case JABBER_SERVER_OPTION_SERVER: + jabber_server_set_server (ptr_server, + JABBER_SERVER_OPTION_STRING(ptr_server, + JABBER_SERVER_OPTION_SERVER)); + break; + } + } + } +} + +/* + * jabber_config_reload: reload Jabber configuration file + */ + +int +jabber_config_reload (void *data, struct t_config_file *config_file) +{ + int rc; + struct t_jabber_server *ptr_server, *next_server; + + /* make C compiler happy */ + (void) data; + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + ptr_server->reloading_from_config = 1; + ptr_server->reloaded_from_config = 0; + } + + rc = weechat_config_reload (config_file); + + ptr_server = jabber_servers; + while (ptr_server) + { + next_server = ptr_server->next_server; + + if (!ptr_server->reloaded_from_config) + { + if (ptr_server->is_connected) + { + weechat_printf (NULL, + _("%s%s: warning: server \"%s\" not found " + "in configuration file, not deleted in " + "memory because it's currently used"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + ptr_server->name); + } + else + jabber_server_free (ptr_server); + } + + ptr_server = next_server; + } + + return rc; +} + +/* + * jabber_config_server_new_option: create a new option for a server + */ + +struct t_config_option * +jabber_config_server_new_option (struct t_config_file *config_file, + struct t_config_section *section, + int index_option, + const char *option_name, + const char *default_value, + const char *value, + int null_value_allowed, + void *callback_change, + void *callback_change_data) +{ + struct t_config_option *new_option; + + new_option = NULL; + + switch (index_option) + { + case JABBER_SERVER_OPTION_USERNAME: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "string", + N_("user name to use on server"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_SERVER: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "string", + N_("hostname/port or IP/port for server"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_PROXY: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "string", + N_("proxy used for this server (optional)"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_IPV6: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "boolean", + N_("use IPv6 protocol for server communication"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_TLS: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "boolean", + N_("use TLS cryptographic protocol for server communication"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_SASL: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "boolean", + N_("use SASL for authentication"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_RESOURCE: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "string", + N_("resource (for example: Home or Work)"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_PASSWORD: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "string", + N_("password"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_LOCAL_ALIAS: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "string", + N_("local alias"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_AUTOCONNECT: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "boolean", + N_("automatically connect to server when WeeChat is starting"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_AUTORECONNECT: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "boolean", + N_("automatically reconnect to server when disconnected"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_AUTORECONNECT_DELAY: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "integer", + N_("delay (in seconds) before trying again to reconnect to " + "server"), + NULL, 0, 65535, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_LOCAL_HOSTNAME: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "string", + N_("custom local hostname/IP for server (optional, if empty " + "local hostname is used)"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_COMMAND: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "string", + N_("command(s) to run when connected to server (many commands " + "should be separated by ';', use '\\;' for a semicolon, " + "special variables $nick, $muc and $server are " + "replaced by their value)"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_COMMAND_DELAY: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "integer", + N_("delay (in seconds) after command was executed (example: " + "give some time for authentication)"), + NULL, 0, 3600, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_AUTOJOIN: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "string", + N_("comma separated list of MUCs to join when connected " + "to server (example: \"#chan1,#chan2,#chan3 key1,key2\")"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_OPTION_AUTOREJOIN: + new_option = weechat_config_new_option ( + config_file, section, + option_name, "boolean", + N_("automatically rejoin MUCs when kicked"), + NULL, 0, 0, + default_value, value, + null_value_allowed, + NULL, NULL, + callback_change, callback_change_data, + NULL, NULL); + break; + case JABBER_SERVER_NUM_OPTIONS: + break; + } + + return new_option; +} + +/* + * jabber_config_server_read_cb: read server option in configuration file + */ + +int +jabber_config_server_read_cb (void *data, struct t_config_file *config_file, + struct t_config_section *section, + const char *option_name, const char *value) +{ + struct t_jabber_server *ptr_server; + int index_option, rc, i; + char *pos_option, *server_name; + + /* make C compiler happy */ + (void) data; + (void) config_file; + (void) section; + + rc = WEECHAT_CONFIG_OPTION_SET_ERROR; + + if (option_name) + { + pos_option = strrchr (option_name, '.'); + if (pos_option) + { + server_name = weechat_strndup (option_name, + pos_option - option_name); + pos_option++; + if (server_name) + { + index_option = jabber_server_search_option (pos_option); + if (index_option >= 0) + { + ptr_server = jabber_server_search (server_name); + if (!ptr_server) + ptr_server = jabber_server_alloc (server_name); + if (ptr_server) + { + if (ptr_server->reloading_from_config + && !ptr_server->reloaded_from_config) + { + for (i = 0; i < JABBER_SERVER_NUM_OPTIONS; i++) + { + weechat_config_option_set (ptr_server->options[i], + NULL, 1); + } + ptr_server->reloaded_from_config = 1; + } + rc = weechat_config_option_set (ptr_server->options[index_option], + value, 1); + } + else + { + weechat_printf (NULL, + _("%s%s: error creating server " + "\"%s\""), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + server_name); + } + } + free (server_name); + } + } + } + + if (rc == WEECHAT_CONFIG_OPTION_SET_ERROR) + { + weechat_printf (NULL, + _("%s%s: error creating server option \"%s\""), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + option_name); + } + + return rc; +} + +/* + * jabber_config_server_write_cb: write server section in configuration file + */ + +void +jabber_config_server_write_cb (void *data, struct t_config_file *config_file, + const char *section_name) +{ + struct t_jabber_server *ptr_server; + int i; + + /* make C compiler happy */ + (void) data; + + weechat_config_write_line (config_file, section_name, NULL); + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (!ptr_server->temp_server || jabber_config_write_temp_servers) + { + for (i = 0; i < JABBER_SERVER_NUM_OPTIONS; i++) + { + weechat_config_write_option (config_file, + ptr_server->options[i]); + } + } + } +} + +/* + * jabber_config_server_create_default_options: create default options for + * servers + */ + +void +jabber_config_server_create_default_options (struct t_config_section *section) +{ + int i; + + for (i = 0; i < JABBER_SERVER_NUM_OPTIONS; i++) + { + jabber_config_server_default[i] = jabber_config_server_new_option ( + jabber_config_file, + section, + i, + jabber_server_option_string[i], + jabber_server_option_default[i], + jabber_server_option_default[i], + 0, + &jabber_config_server_default_change_cb, + jabber_server_option_string[i]); + } +} + +/* + * jabber_config_init: init Jabber configuration file + * return: 1 if ok, 0 if error + */ + +int +jabber_config_init () +{ + struct t_config_section *ptr_section; + + jabber_config_file = weechat_config_new (JABBER_CONFIG_NAME, + &jabber_config_reload, NULL); + if (!jabber_config_file) + return 0; + + /* look */ + ptr_section = weechat_config_new_section (jabber_config_file, "look", + 0, 0, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL); + if (!ptr_section) + { + weechat_config_free (jabber_config_file); + return 0; + } + + jabber_config_look_color_nicks_in_server_messages = weechat_config_new_option ( + jabber_config_file, ptr_section, + "color_nicks_in_server_messages", "boolean", + N_("use nick color in messages from server"), + NULL, 0, 0, "on", NULL, 0, NULL, NULL, + NULL, NULL, NULL, NULL); + jabber_config_look_one_server_buffer = weechat_config_new_option ( + jabber_config_file, ptr_section, + "one_server_buffer", "boolean", + N_("use same buffer for all servers"), + NULL, 0, 0, "off", NULL, 0, NULL, NULL, + &jabber_config_change_look_one_server_buffer, NULL, NULL, NULL); + jabber_config_look_open_near_server = weechat_config_new_option ( + jabber_config_file, ptr_section, + "open_near_server", "boolean", + N_("open new MUCs/privates near server"), + NULL, 0, 0, "off", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_look_nick_prefix = weechat_config_new_option ( + jabber_config_file, ptr_section, + "nick_prefix", "string", + N_("text to display before nick in chat window"), + NULL, 0, 0, "", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_look_nick_suffix = weechat_config_new_option ( + jabber_config_file, ptr_section, + "nick_suffix", "string", + N_("text to display after nick in chat window"), + NULL, 0, 0, "", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_look_nick_completion_smart = weechat_config_new_option ( + jabber_config_file, ptr_section, + "nick_completion_smart", "boolean", + N_("smart completion for nicks (completes with last speakers first)"), + NULL, 0, 0, "on", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_look_display_away = weechat_config_new_option ( + jabber_config_file, ptr_section, + "display_away", "integer", + N_("display message when (un)marking as away"), + "off|local|muc", 0, 0, "local", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_look_display_muc_modes = weechat_config_new_option ( + jabber_config_file, ptr_section, + "display_muc_modes", "boolean", + N_("display MUC modes in \"buffer_name\" bar item"), + NULL, 0, 0, "on", NULL, 0, NULL, NULL, + &jabber_config_change_look_display_muc_modes, NULL, NULL, NULL); + jabber_config_look_hide_nickserv_pwd = weechat_config_new_option ( + jabber_config_file, ptr_section, + "hide_nickserv_pwd", "boolean", + N_("hide password displayed by nickserv"), + NULL, 0, 0, "on", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_look_highlight_tags = weechat_config_new_option ( + jabber_config_file, ptr_section, + "highlight_tags", "string", + N_("comma separated list of tags for messages that may produce " + "highlight (usually any message from another user, not server " + "messages,..)"), + NULL, 0, 0, "jabber_chat_msg,jabber_notice", NULL, 0, NULL, NULL, + &jabber_config_change_look_highlight_tags, NULL, NULL, NULL); + jabber_config_look_show_away_once = weechat_config_new_option ( + jabber_config_file, ptr_section, + "show_away_once", "boolean", + N_("show remote away message only once in private"), + NULL, 0, 0, "on", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_look_smart_filter = weechat_config_new_option ( + jabber_config_file, ptr_section, + "smart_filter", "boolean", + N_("filter join/part/quit messages for a nick if not speaking for " + "some minutes on MUC (you must create a filter on tag " + "\"jabber_smart_filter\")"), + NULL, 0, 0, "off", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_look_smart_filter_delay = weechat_config_new_option ( + jabber_config_file, ptr_section, + "smart_filter_delay", "integer", + N_("delay for filtering join/part/quit messages (in minutes)"), + NULL, 1, 60*24*7, "5", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_look_notice_as_pv = weechat_config_new_option ( + jabber_config_file, ptr_section, + "notice_as_pv", "boolean", + N_("display notices as private messages"), + NULL, 0, 0, "off", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + + /* color */ + ptr_section = weechat_config_new_section (jabber_config_file, "color", + 0, 0, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL); + if (!ptr_section) + { + weechat_config_free (jabber_config_file); + return 0; + } + + jabber_config_color_message_join = weechat_config_new_option ( + jabber_config_file, ptr_section, + "message_join", "color", + N_("color for text in join messages"), + NULL, -1, 0, "green", NULL, 0, NULL, NULL, + NULL, NULL, NULL, NULL); + jabber_config_color_message_quit = weechat_config_new_option ( + jabber_config_file, ptr_section, + "message_quit", "color", + N_("color for text in part/quit messages"), + NULL, -1, 0, "red", NULL, 0, NULL, NULL, + NULL, NULL, NULL, NULL); + jabber_config_color_input_nick = weechat_config_new_option ( + jabber_config_file, ptr_section, + "input_nick", "color", + N_("color for nick in input bar"), + NULL, -1, 0, "lightcyan", NULL, 0, NULL, NULL, + &jabber_config_change_color_input_nick, NULL, NULL, NULL); + + /* network */ + ptr_section = weechat_config_new_section (jabber_config_file, "network", + 0, 0, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL); + if (!ptr_section) + { + weechat_config_free (jabber_config_file); + return 0; + } + + jabber_config_network_default_msg_part = weechat_config_new_option ( + jabber_config_file, ptr_section, + "default_msg_part", "string", + N_("default part message (leaving MUC) ('%v' will be replaced by " + "WeeChat version in string)"), + NULL, 0, 0, "WeeChat %v", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_network_default_msg_quit = weechat_config_new_option ( + jabber_config_file, ptr_section, + "default_msg_quit", "string", + N_("default quit message (disconnecting from server) ('%v' will be " + "replaced by WeeChat version in string)"), + NULL, 0, 0, "WeeChat %v", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_network_lag_check = weechat_config_new_option ( + jabber_config_file, ptr_section, + "lag_check", "integer", + N_("interval between two checks for lag (in seconds, 0 = never " + "check)"), + NULL, 0, INT_MAX, "60", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_network_lag_min_show = weechat_config_new_option ( + jabber_config_file, ptr_section, + "lag_min_show", "integer", + N_("minimum lag to show (in seconds)"), + NULL, 0, INT_MAX, "1", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_network_lag_disconnect = weechat_config_new_option ( + jabber_config_file, ptr_section, + "lag_disconnect", "integer", + N_("disconnect after important lag (in minutes, 0 = never " + "disconnect)"), + NULL, 0, INT_MAX, "5", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_network_anti_flood = weechat_config_new_option ( + jabber_config_file, ptr_section, + "anti_flood", "integer", + N_("anti-flood: # seconds between two user messages (0 = no " + "anti-flood)"), + NULL, 0, 5, "2", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_network_colors_receive = weechat_config_new_option ( + jabber_config_file, ptr_section, + "colors_receive", "boolean", + N_("when off, colors codes are ignored in incoming messages"), + NULL, 0, 0, "on", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + jabber_config_network_colors_send = weechat_config_new_option ( + jabber_config_file, ptr_section, + "colors_send", "boolean", + N_("allow user to send colors with special codes (^Cb=bold, " + "^Ccxx=color, ^Ccxx,yy=color+background, ^Cu=underline, " + "^Cr=reverse)"), + NULL, 0, 0, "on", NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL); + + /* server_default */ + ptr_section = weechat_config_new_section (jabber_config_file, "server_default", + 0, 0, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL); + if (!ptr_section) + { + weechat_config_free (jabber_config_file); + return 0; + } + + jabber_config_section_server_default = ptr_section; + + jabber_config_server_create_default_options (ptr_section); + + /* server */ + ptr_section = weechat_config_new_section (jabber_config_file, "server", + 0, 0, + &jabber_config_server_read_cb, NULL, + &jabber_config_server_write_cb, NULL, + NULL, NULL, + NULL, NULL, + NULL, NULL); + if (!ptr_section) + { + weechat_config_free (jabber_config_file); + return 0; + } + + jabber_config_section_server = ptr_section; + + hook_config_color_nicks_number = weechat_hook_config ("weechat.look.color_nicks_number", + &jabber_config_change_look_color_nicks_number, NULL); + + return 1; +} + +/* + * jabber_config_read: read Jabber configuration file + */ + +int +jabber_config_read () +{ + return weechat_config_read (jabber_config_file); +} + +/* + * jabber_config_write: write Jabber configuration file + */ + +int +jabber_config_write (int write_temp_servers) +{ + jabber_config_write_temp_servers = write_temp_servers; + + return weechat_config_write (jabber_config_file); +} + +/* + * jabber_config_free: free Jabber configuration + */ + +void +jabber_config_free () +{ + weechat_config_free (jabber_config_file); + + if (hook_config_color_nicks_number) + { + weechat_unhook (hook_config_color_nicks_number); + hook_config_color_nicks_number = NULL; + } +} diff --git a/src/plugins/jabber/jabber-config.h b/src/plugins/jabber/jabber-config.h new file mode 100644 index 000000000..466ea3539 --- /dev/null +++ b/src/plugins/jabber/jabber-config.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_CONFIG_H +#define __WEECHAT_JABBER_CONFIG_H 1 + +#define JABBER_CONFIG_NAME "jabber" + +#define JABBER_CONFIG_DISPLAY_AWAY_OFF 0 +#define JABBER_CONFIG_DISPLAY_AWAY_LOCAL 1 +#define JABBER_CONFIG_DISPLAY_AWAY_MUC 2 + + +extern struct t_config_file *jabber_config_file; +extern struct t_config_section *jabber_config_section_server_default; +extern struct t_config_section *jabber_config_section_server; + +extern struct t_config_option *jabber_config_look_color_nicks_in_server_messages; +extern struct t_config_option *jabber_config_look_one_server_buffer; +extern struct t_config_option *jabber_config_look_open_near_server; +extern struct t_config_option *jabber_config_look_nick_prefix; +extern struct t_config_option *jabber_config_look_nick_suffix; +extern struct t_config_option *jabber_config_look_nick_completion_smart; +extern struct t_config_option *jabber_config_look_display_away; +extern struct t_config_option *jabber_config_look_display_muc_modes; +extern struct t_config_option *jabber_config_look_hide_nickserv_pwd; +extern struct t_config_option *jabber_config_look_highlight_tags; +extern struct t_config_option *jabber_config_look_show_away_once; +extern struct t_config_option *jabber_config_look_smart_filter; +extern struct t_config_option *jabber_config_look_smart_filter_delay; +extern struct t_config_option *jabber_config_look_notice_as_pv; + +extern struct t_config_option *jabber_config_color_message_join; +extern struct t_config_option *jabber_config_color_message_quit; +extern struct t_config_option *jabber_config_color_input_nick; + +extern struct t_config_option *jabber_config_network_default_msg_part; +extern struct t_config_option *jabber_config_network_default_msg_quit; +extern struct t_config_option *jabber_config_network_lag_check; +extern struct t_config_option *jabber_config_network_lag_min_show; +extern struct t_config_option *jabber_config_network_lag_disconnect; +extern struct t_config_option *jabber_config_network_anti_flood; +extern struct t_config_option *jabber_config_network_colors_receive; +extern struct t_config_option *jabber_config_network_colors_send; + +extern struct t_config_option *jabber_config_server_default[]; + +extern void jabber_config_server_change_cb (void *data, + struct t_config_option *option); +struct t_config_option *jabber_config_server_new_option (struct t_config_file *config_file, + struct t_config_section *section, + int index_option, + const char *option_name, + const char *default_value, + const char *value, + int null_value_allowed, + void *callback_change, + void *callback_change_data); +extern int jabber_config_init (); +extern int jabber_config_read (); +extern int jabber_config_write (int write_temp_servers); +extern void jabber_config_free (); + +#endif /* jabber-config.h */ diff --git a/src/plugins/jabber/jabber-debug.c b/src/plugins/jabber/jabber-debug.c new file mode 100644 index 000000000..b5914f8a5 --- /dev/null +++ b/src/plugins/jabber/jabber-debug.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber-debug.c: debug functions for Jabber plugin */ + + +#include <stdlib.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-debug.h" +#include "jabber-server.h" + + +struct t_gui_buffer *jabber_debug_buffer = NULL; + + +/* + * jabber_debug_buffer_close_cb: callback called when Jabber debug buffer is + * closed + */ + +int +jabber_debug_buffer_close_cb (void *data, struct t_gui_buffer *buffer) +{ + /* make C compiler happy */ + (void) data; + (void) buffer; + + jabber_debug_buffer = NULL; + + return WEECHAT_RC_OK; +} + +/* + * jabber_debug_printf: print a message on Jabber debug buffer + */ + +void +jabber_debug_printf (struct t_jabber_server *server, int send, int modified, + const char *message) +{ + char *buf; + + if (!weechat_jabber_plugin->debug || !message) + return; + + if (!jabber_debug_buffer) + { + jabber_debug_buffer = weechat_buffer_search ("jabber", + JABBER_DEBUG_BUFFER_NAME); + if (!jabber_debug_buffer) + { + jabber_debug_buffer = weechat_buffer_new (JABBER_DEBUG_BUFFER_NAME, + NULL, NULL, + &jabber_debug_buffer_close_cb, NULL); + + /* failed to create buffer ? then return */ + if (!jabber_debug_buffer) + return; + + weechat_buffer_set (jabber_debug_buffer, + "title", _("Jabber debug messages")); + + weechat_buffer_set (jabber_debug_buffer, "short_name", JABBER_DEBUG_BUFFER_NAME); + weechat_buffer_set (jabber_debug_buffer, "localvar_set_server", JABBER_DEBUG_BUFFER_NAME); + weechat_buffer_set (jabber_debug_buffer, "localvar_set_muc", JABBER_DEBUG_BUFFER_NAME); + weechat_buffer_set (jabber_debug_buffer, "localvar_set_no_log", "1"); + + /* disabled all highlights on this debug buffer */ + weechat_buffer_set (jabber_debug_buffer, "highlight_words", "-"); + } + } + + buf = weechat_iconv_to_internal (NULL, message); + + weechat_printf (jabber_debug_buffer, + "%s%s%s%s%s%s\t%s", + (server) ? weechat_color ("chat_server") : "", + (server) ? server->name : "", + (server) ? " " : "", + (send) ? + weechat_color ("chat_prefix_quit") : + weechat_color ("chat_prefix_join"), + (iks_is_secure (server->iks_parser)) ? "* " : "", + (send) ? + ((modified) ? JABBER_DEBUG_PREFIX_SEND_MOD : JABBER_DEBUG_PREFIX_SEND) : + ((modified) ? JABBER_DEBUG_PREFIX_RECV_MOD : JABBER_DEBUG_PREFIX_RECV), + (buf) ? buf : message); + if (buf) + free (buf); +} + +/* + * jabber_debug_signal_debug_dump_cb: dump Jabber data in WeeChat log file + */ + +int +jabber_debug_signal_debug_dump_cb (void *data, const char *signal, + const char *type_data, void *signal_data) +{ + /* make C compiler happy */ + (void) data; + (void) signal; + (void) type_data; + (void) signal_data; + + weechat_log_printf (""); + weechat_log_printf ("***** \"%s\" plugin dump *****", + weechat_plugin->name); + + jabber_server_print_log (); + + weechat_log_printf (""); + weechat_log_printf ("***** End of \"%s\" plugin dump *****", + weechat_plugin->name); + + return WEECHAT_RC_OK; +} + +/* + * jabber_debug_init: initialize debug for Jabber plugin + */ + +void +jabber_debug_init () +{ + weechat_hook_signal ("debug_dump", &jabber_debug_signal_debug_dump_cb, NULL); +} diff --git a/src/plugins/jabber/jabber-debug.h b/src/plugins/jabber/jabber-debug.h new file mode 100644 index 000000000..52a1379fb --- /dev/null +++ b/src/plugins/jabber/jabber-debug.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_DEBUG_H +#define __WEECHAT_JABBER_DEBUG_H 1 + +#define JABBER_DEBUG_BUFFER_NAME "jabber_debug" + +#define JABBER_DEBUG_PREFIX_RECV "-->" +#define JABBER_DEBUG_PREFIX_RECV_MOD "==>" +#define JABBER_DEBUG_PREFIX_SEND "<--" +#define JABBER_DEBUG_PREFIX_SEND_MOD "<==" + +struct t_jabber_server; + +extern void jabber_debug_printf (struct t_jabber_server *server, int send, + int modified, const char *message); +extern void jabber_debug_init (); + +#endif /* jabber-debug.h */ diff --git a/src/plugins/jabber/jabber-display.c b/src/plugins/jabber/jabber-display.c new file mode 100644 index 000000000..7eace16c7 --- /dev/null +++ b/src/plugins/jabber/jabber-display.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber-display.c: display functions for Jabber plugin */ + + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-command.h" +#include "jabber-config.h" +#include "jabber-server.h" + + +/* + * jabber_display_server: display server infos + */ + +void +jabber_display_server (struct t_jabber_server *server, int with_detail) +{ + int num_mucs, num_pv; + + if (with_detail) + { + weechat_printf (NULL, ""); + weechat_printf (NULL, _("%sServer: %s%s %s[%s%s%s]%s%s"), + JABBER_COLOR_CHAT, + JABBER_COLOR_CHAT_SERVER, + server->name, + JABBER_COLOR_CHAT_DELIMITERS, + JABBER_COLOR_CHAT, + (server->is_connected) ? + _("connected") : _("not connected"), + JABBER_COLOR_CHAT_DELIMITERS, + JABBER_COLOR_CHAT, + (server->temp_server) ? _(" (temporary)") : ""); + + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_USERNAME])) + weechat_printf (NULL, " username . . . . . . : ('%s')", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_USERNAME)); + else + weechat_printf (NULL, " username . . . . . . : %s'%s'", + JABBER_COLOR_CHAT_HOST, + weechat_config_string (server->options[JABBER_SERVER_OPTION_USERNAME])); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_SERVER])) + weechat_printf (NULL, " server . . . . . . . : ('%s')", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_SERVER)); + else + weechat_printf (NULL, " server . . . . . . . : %s'%s'", + JABBER_COLOR_CHAT_HOST, + weechat_config_string (server->options[JABBER_SERVER_OPTION_SERVER])); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_PROXY])) + weechat_printf (NULL, " proxy. . . . . . . . : ('%s')", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_PROXY)); + else + weechat_printf (NULL, " proxy. . . . . . . . : %s'%s'", + JABBER_COLOR_CHAT_HOST, + weechat_config_string (server->options[JABBER_SERVER_OPTION_PROXY])); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_IPV6])) + weechat_printf (NULL, " ipv6 . . . . . . . . : (%s)", + (JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_IPV6)) ? + _("on") : _("off")); + else + weechat_printf (NULL, " ipv6 . . . . . . . . : %s%s", + JABBER_COLOR_CHAT_HOST, + weechat_config_boolean (server->options[JABBER_SERVER_OPTION_IPV6]) ? + _("on") : _("off")); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_TLS])) + weechat_printf (NULL, " tls. . . . . . . . . : (%s)", + (JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_TLS)) ? + _("on") : _("off")); + else + weechat_printf (NULL, " tls. . . . . . . . . : %s%s", + JABBER_COLOR_CHAT_HOST, + weechat_config_boolean (server->options[JABBER_SERVER_OPTION_TLS]) ? + _("on") : _("off")); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_SASL])) + weechat_printf (NULL, " sasl . . . . . . . . : (%s)", + (JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_SASL)) ? + _("on") : _("off")); + else + weechat_printf (NULL, " sasl . . . . . . . . : %s%s", + JABBER_COLOR_CHAT_HOST, + weechat_config_boolean (server->options[JABBER_SERVER_OPTION_SASL]) ? + _("on") : _("off")); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_RESOURCE])) + weechat_printf (NULL, " resource . . . . . . : ('%s')", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_RESOURCE)); + else + weechat_printf (NULL, " resource . . . . . . : %s'%s'", + JABBER_COLOR_CHAT_HOST, + weechat_config_string (server->options[JABBER_SERVER_OPTION_RESOURCE])); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_PASSWORD])) + weechat_printf (NULL, " password . . . . . . : %s", + _("(hidden)")); + else + weechat_printf (NULL, " password . . . . . . : %s%s", + JABBER_COLOR_CHAT_HOST, + _("(hidden)")); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_LOCAL_ALIAS])) + weechat_printf (NULL, " local_alias. . . . . : ('%s')", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_LOCAL_ALIAS)); + else + weechat_printf (NULL, " local_alias. . . . . : %s'%s'", + JABBER_COLOR_CHAT_HOST, + weechat_config_string (server->options[JABBER_SERVER_OPTION_LOCAL_ALIAS])); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_AUTOCONNECT])) + weechat_printf (NULL, " autoconnect. . . . . : (%s)", + (JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_AUTOCONNECT)) ? + _("on") : _("off")); + else + weechat_printf (NULL, " autoconnect. . . . . : %s%s", + JABBER_COLOR_CHAT_HOST, + weechat_config_boolean (server->options[JABBER_SERVER_OPTION_AUTOCONNECT]) ? + _("on") : _("off")); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_AUTORECONNECT])) + weechat_printf (NULL, " autoreconnect. . . . : (%s)", + (JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_AUTORECONNECT)) ? + _("on") : _("off")); + else + weechat_printf (NULL, " autoreconnect. . . . : %s%s", + JABBER_COLOR_CHAT_HOST, + weechat_config_boolean (server->options[JABBER_SERVER_OPTION_AUTORECONNECT]) ? + _("on") : _("off")); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_AUTORECONNECT_DELAY])) + weechat_printf (NULL, " autoreconnect_delay. : (%d %s)", + JABBER_SERVER_OPTION_INTEGER(server, JABBER_SERVER_OPTION_AUTORECONNECT_DELAY), + NG_("second", "seconds", JABBER_SERVER_OPTION_INTEGER(server, JABBER_SERVER_OPTION_AUTORECONNECT_DELAY))); + else + weechat_printf (NULL, " autoreconnect_delay. : %s%d %s", + JABBER_COLOR_CHAT_HOST, + weechat_config_integer (server->options[JABBER_SERVER_OPTION_AUTORECONNECT_DELAY]), + NG_("second", "seconds", weechat_config_integer (server->options[JABBER_SERVER_OPTION_AUTORECONNECT_DELAY]))); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_LOCAL_HOSTNAME])) + weechat_printf (NULL, " local_hostname . . . : ('%s')", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_LOCAL_HOSTNAME)); + else + weechat_printf (NULL, " local_hostname . . . : %s'%s'", + JABBER_COLOR_CHAT_HOST, + weechat_config_string (server->options[JABBER_SERVER_OPTION_LOCAL_HOSTNAME])); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_COMMAND])) + weechat_printf (NULL, " command. . . . . . . : ('%s')", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_COMMAND)); + else + weechat_printf (NULL, " command. . . . . . . : %s'%s'", + JABBER_COLOR_CHAT_HOST, + weechat_config_string (server->options[JABBER_SERVER_OPTION_COMMAND])); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_COMMAND_DELAY])) + weechat_printf (NULL, " command_delay. . . . : (%d %s)", + JABBER_SERVER_OPTION_INTEGER(server, JABBER_SERVER_OPTION_COMMAND_DELAY), + NG_("second", "seconds", JABBER_SERVER_OPTION_INTEGER(server, JABBER_SERVER_OPTION_COMMAND_DELAY))); + else + weechat_printf (NULL, " command_delay. . . . : %s%d %s", + JABBER_COLOR_CHAT_HOST, + weechat_config_integer (server->options[JABBER_SERVER_OPTION_COMMAND_DELAY]), + NG_("second", "seconds", weechat_config_integer (server->options[JABBER_SERVER_OPTION_COMMAND_DELAY]))); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_AUTOJOIN])) + weechat_printf (NULL, " autojoin . . . . . . : ('%s')", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_AUTOJOIN)); + else + weechat_printf (NULL, " autojoin . . . . . . : %s'%s'", + JABBER_COLOR_CHAT_HOST, + weechat_config_string (server->options[JABBER_SERVER_OPTION_AUTOJOIN])); + if (weechat_config_option_is_null (server->options[JABBER_SERVER_OPTION_AUTOREJOIN])) + weechat_printf (NULL, " autorejoin . . . . . : (%s)", + (JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_AUTOREJOIN)) ? + _("on") : _("off")); + else + weechat_printf (NULL, " autorejoin . . . . . : %s%s", + JABBER_COLOR_CHAT_HOST, + weechat_config_boolean (server->options[JABBER_SERVER_OPTION_AUTOREJOIN]) ? + _("on") : _("off")); + } + else + { + if (server->is_connected) + { + num_mucs = jabber_server_get_muc_count (server); + num_pv = jabber_server_get_pv_count (server); + weechat_printf (NULL, " %s %s%s %s[%s%s%s]%s%s, %d %s, %d pv", + (server->is_connected) ? "*" : " ", + JABBER_COLOR_CHAT_SERVER, + server->name, + JABBER_COLOR_CHAT_DELIMITERS, + JABBER_COLOR_CHAT, + (server->is_connected) ? + _("connected") : _("not connected"), + JABBER_COLOR_CHAT_DELIMITERS, + JABBER_COLOR_CHAT, + (server->temp_server) ? _(" (temporary)") : "", + num_mucs, + NG_("MUC", "MUCs", num_mucs), + num_pv); + } + else + { + weechat_printf (NULL, " %s%s%s%s", + JABBER_COLOR_CHAT_SERVER, + server->name, + JABBER_COLOR_CHAT, + (server->temp_server) ? _(" (temporary)") : ""); + } + } +} diff --git a/src/plugins/jabber/jabber-display.h b/src/plugins/jabber/jabber-display.h new file mode 100644 index 000000000..bec2e51c9 --- /dev/null +++ b/src/plugins/jabber/jabber-display.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_DISPLAY_H +#define __WEECHAT_JABBER_DISPLAY_H 1 + +extern void jabber_display_server (struct t_jabber_server *server, + int with_detail); + +#endif /* jabber-display.h */ diff --git a/src/plugins/jabber/jabber-info.c b/src/plugins/jabber/jabber-info.c new file mode 100644 index 000000000..4279d6199 --- /dev/null +++ b/src/plugins/jabber/jabber-info.c @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber-info.c: info and infolist hooks for Jabber plugin */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-buddy.h" +#include "jabber-muc.h" +#include "jabber-server.h" + + +/* + * jabber_info_create_string_with_pointer: create a string with a pointer inside + * a Jabber structure + */ + +void +jabber_info_create_string_with_pointer (char **string, void *pointer) +{ + if (*string) + { + free (*string); + *string = NULL; + } + if (pointer) + { + *string = malloc (64); + if (*string) + { + snprintf (*string, 64 - 1, "0x%lx", (long unsigned int)pointer); + } + } +} + +/* + * jabber_info_get_info_cb: callback called when Jabber info is asked + */ + +const char * +jabber_info_get_info_cb (void *data, const char *info_name, + const char *arguments) +{ + char *pos_comma, *pos_comma2, *server, *muc, *host; + struct t_jabber_server *ptr_server; + struct t_jabber_muc *ptr_muc; + + /* make C compiler happy */ + (void) data; + + if (weechat_strcasecmp (info_name, "jabber_buffer") == 0) + { + if (arguments && arguments[0]) + { + server = NULL; + muc = NULL; + host = NULL; + ptr_server = NULL; + ptr_muc = NULL; + + pos_comma = strchr (arguments, ','); + if (pos_comma) + { + server = weechat_strndup (arguments, pos_comma - arguments); + pos_comma2 = strchr (pos_comma + 1, ','); + if (pos_comma2) + { + muc = weechat_strndup (pos_comma + 1, + pos_comma2 - pos_comma - 1); + host = strdup (pos_comma2 + 1); + } + else + muc = strdup (pos_comma + 1); + } + + /* replace MUC by buddy in host if MUC is not a MUC (private ?) */ + if (muc && host) + { + //if (!jabber_muc_is_muc (muc)) + //{ + // free (muc); + // muc = NULL; + // buddy = jabber_xmpp_get_buddy_from_host (host); + // if (buddy) + // muc = strdup (buddy); + //} + } + + /* search for server or MUC buffer */ + if (server) + { + ptr_server = jabber_server_search (server); + if (ptr_server && muc) + ptr_muc = jabber_muc_search (ptr_server, muc); + } + + if (server) + free (server); + if (muc) + free (muc); + if (host) + free (host); + + if (ptr_muc) + { + jabber_info_create_string_with_pointer (&ptr_muc->buffer_as_string, + ptr_muc->buffer); + return ptr_muc->buffer_as_string; + } + if (ptr_server) + { + jabber_info_create_string_with_pointer (&ptr_server->buffer_as_string, + ptr_server->buffer); + return ptr_server->buffer_as_string; + } + } + } + + return NULL; +} + +/* + * jabber_info_get_infolist_cb: callback called when Jabber infolist is asked + */ + +struct t_infolist * +jabber_info_get_infolist_cb (void *data, const char *infolist_name, + void *pointer, const char *arguments) +{ + struct t_infolist *ptr_infolist; + struct t_jabber_server *ptr_server; + struct t_jabber_muc *ptr_muc; + struct t_jabber_buddy *ptr_buddy; + char *pos_comma, *server_name; + + /* make C compiler happy */ + (void) data; + + if (!infolist_name || !infolist_name[0]) + return NULL; + + if (weechat_strcasecmp (infolist_name, "jabber_server") == 0) + { + if (pointer && !jabber_server_valid (pointer)) + return NULL; + + ptr_infolist = weechat_infolist_new (); + if (ptr_infolist) + { + if (pointer) + { + /* build list with only one server */ + if (!jabber_server_add_to_infolist (ptr_infolist, pointer)) + { + weechat_infolist_free (ptr_infolist); + return NULL; + } + return ptr_infolist; + } + else + { + /* build list with all servers */ + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (!jabber_server_add_to_infolist (ptr_infolist, ptr_server)) + { + weechat_infolist_free (ptr_infolist); + return NULL; + } + } + return ptr_infolist; + } + } + } + else if (weechat_strcasecmp (infolist_name, "jabber_muc") == 0) + { + if (arguments && arguments[0]) + { + ptr_server = jabber_server_search (arguments); + if (ptr_server) + { + if (pointer && !jabber_muc_valid (ptr_server, pointer)) + return NULL; + + ptr_infolist = weechat_infolist_new (); + if (ptr_infolist) + { + if (pointer) + { + /* build list with only one MUC */ + if (!jabber_muc_add_to_infolist (ptr_infolist, pointer)) + { + weechat_infolist_free (ptr_infolist); + return NULL; + } + return ptr_infolist; + } + else + { + /* build list with all MUCs of server */ + for (ptr_muc = ptr_server->mucs; ptr_muc; + ptr_muc = ptr_muc->next_muc) + { + if (!jabber_muc_add_to_infolist (ptr_infolist, + ptr_muc)) + { + weechat_infolist_free (ptr_infolist); + return NULL; + } + } + return ptr_infolist; + } + } + } + } + } + else if (weechat_strcasecmp (infolist_name, "jabber_buddy") == 0) + { + if (arguments && arguments[0]) + { + ptr_server = NULL; + ptr_muc = NULL; + pos_comma = strchr (arguments, ','); + if (pos_comma) + { + server_name = weechat_strndup (arguments, pos_comma - arguments); + if (server_name) + { + ptr_server = jabber_server_search (server_name); + if (ptr_server) + { + ptr_muc = jabber_muc_search (ptr_server, + pos_comma + 1); + } + free (server_name); + } + } + if (ptr_muc) + { + if (pointer && !jabber_buddy_valid (NULL, ptr_muc, pointer)) + return NULL; + + ptr_infolist = weechat_infolist_new (); + if (ptr_infolist) + { + if (pointer) + { + /* build list with only one buddy */ + if (!jabber_buddy_add_to_infolist (ptr_infolist, pointer)) + { + weechat_infolist_free (ptr_infolist); + return NULL; + } + return ptr_infolist; + } + else + { + /* build list with all buddies of MUC */ + for (ptr_buddy = ptr_muc->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + if (!jabber_buddy_add_to_infolist (ptr_infolist, + ptr_buddy)) + { + weechat_infolist_free (ptr_infolist); + return NULL; + } + } + return ptr_infolist; + } + } + } + else if (ptr_server) + { + if (pointer && !jabber_buddy_valid (ptr_server, NULL, pointer)) + return NULL; + + ptr_infolist = weechat_infolist_new (); + if (ptr_infolist) + { + if (pointer) + { + /* build list with only one buddy */ + if (!jabber_buddy_add_to_infolist (ptr_infolist, pointer)) + { + weechat_infolist_free (ptr_infolist); + return NULL; + } + return ptr_infolist; + } + else + { + /* build list with all buddies of server */ + for (ptr_buddy = ptr_server->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + if (!jabber_buddy_add_to_infolist (ptr_infolist, + ptr_buddy)) + { + weechat_infolist_free (ptr_infolist); + return NULL; + } + } + return ptr_infolist; + } + } + } + } + } + + return NULL; +} + +/* + * jabber_info_init: initialize info and infolist hooks for Jabber plugin + */ + +void +jabber_info_init () +{ + /* info hooks */ + weechat_hook_info ("jabber_buffer", + N_("get buffer pointer for a Jabber server/MUC"), + &jabber_info_get_info_cb, NULL); + + /* infolist hooks */ + weechat_hook_infolist ("jabber_server", + N_("list of Jabber servers"), + &jabber_info_get_infolist_cb, NULL); + weechat_hook_infolist ("jabber_muc", + N_("list of MUCs for a Jabber server"), + &jabber_info_get_infolist_cb, NULL); + weechat_hook_infolist ("jabber_buddy", + N_("list of buddies for a Jabber server or MUC"), + &jabber_info_get_infolist_cb, NULL); +} diff --git a/src/plugins/jabber/jabber-info.h b/src/plugins/jabber/jabber-info.h new file mode 100644 index 000000000..364a0c1ae --- /dev/null +++ b/src/plugins/jabber/jabber-info.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_INFO_H +#define __WEECHAT_JABBER_INFO_H 1 + +extern void jabber_info_init (); + +#endif /* jabber-info.h */ diff --git a/src/plugins/jabber/jabber-input.c b/src/plugins/jabber/jabber-input.c new file mode 100644 index 000000000..42f2b83c4 --- /dev/null +++ b/src/plugins/jabber/jabber-input.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber-input.c: Jabber input data (read from user) */ + + +#include <stdlib.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-buffer.h" +#include "jabber-server.h" +#include "jabber-muc.h" +#include "jabber-buddy.h" +#include "jabber-config.h" +#include "jabber-xmpp.h" + + +/* + * jabber_input_user_message_display: display user message + */ + +void +jabber_input_user_message_display (struct t_gui_buffer *buffer, + const char *text) +{ + struct t_jabber_buddy *ptr_buddy; + const char *local_name; + + JABBER_GET_SERVER_MUC(buffer); + + local_name = jabber_server_get_local_name (ptr_server); + + if (ptr_muc) + { + if (ptr_muc->type == JABBER_MUC_TYPE_MUC) + ptr_buddy = jabber_buddy_search (NULL, ptr_muc, local_name); + else + ptr_buddy = NULL; + + weechat_printf_tags (buffer, + jabber_xmpp_tags ("chat_msg", "no_highlight"), + "%s%s", + jabber_buddy_as_prefix ((ptr_buddy) ? ptr_buddy : NULL, + (ptr_buddy) ? NULL : local_name, + JABBER_COLOR_CHAT_NICK_SELF), + text); + } +} + +/* + * jabber_input_data_cb: callback for input data in a buffer + */ + +int +jabber_input_data_cb (void *data, struct t_gui_buffer *buffer, + const char *input_data) +{ + const char *ptr_data; + char *msg; + + /* make C compiler happy */ + (void) data; + + JABBER_GET_SERVER_MUC(buffer); + + if (ptr_muc) + { + ptr_data = ((input_data[0] == '/') && (input_data[1] == '/')) ? + input_data + 1 : input_data; + + msg = strdup (ptr_data); + if (msg) + { + jabber_xmpp_send_chat_message (ptr_server, ptr_muc, msg); + jabber_input_user_message_display (buffer, msg); + free (msg); + } + } + else + { + weechat_printf (buffer, + _("%s: this buffer is not a MUC!"), + JABBER_PLUGIN_NAME); + } + + return WEECHAT_RC_OK; +} diff --git a/src/plugins/jabber/jabber-input.h b/src/plugins/jabber/jabber-input.h new file mode 100644 index 000000000..979546f96 --- /dev/null +++ b/src/plugins/jabber/jabber-input.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_INPUT_H +#define __WEECHAT_JABBER_INPUT_H 1 + +struct t_gui_buffer; + +extern void jabber_input_user_message_display (struct t_gui_buffer *buffer, + const char *text); +extern int jabber_input_data_cb (void *data, struct t_gui_buffer *buffer, + const char *input_data); + +#endif /* jabber-input.h */ diff --git a/src/plugins/jabber/jabber-muc.c b/src/plugins/jabber/jabber-muc.c new file mode 100644 index 000000000..80a1e8787 --- /dev/null +++ b/src/plugins/jabber/jabber-muc.c @@ -0,0 +1,662 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber-muc.c: jabber MUC management */ + + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-muc.h" +#include "jabber-buffer.h" +#include "jabber-config.h" +#include "jabber-buddy.h" +#include "jabber-server.h" +#include "jabber-input.h" + + +/* + * jabber_muc_valid: check if a MUC pointer exists for a server + * return 1 if MUC exists + * 0 if MUC is not found + */ + +int +jabber_muc_valid (struct t_jabber_server *server, struct t_jabber_muc *muc) +{ + struct t_jabber_muc *ptr_muc; + + if (!server) + return 0; + + for (ptr_muc = server->mucs; ptr_muc; ptr_muc = ptr_muc->next_muc) + { + if (ptr_muc == muc) + return 1; + } + + /* MUC not found */ + return 0; +} + +/* + * jabber_muc_new: allocate a new MUC for a server and add it to MUC list + */ + +struct t_jabber_muc * +jabber_muc_new (struct t_jabber_server *server, int muc_type, + const char *muc_name, int switch_to_muc) +{ + struct t_jabber_muc *new_muc; + struct t_gui_buffer *new_buffer; + char *buffer_name; + + /* alloc memory for new MUCl */ + if ((new_muc = malloc (sizeof (*new_muc))) == NULL) + { + weechat_printf (NULL, + _("%s%s: cannot allocate new MUC"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME); + return NULL; + } + + /* create buffer for MUC (or use existing one) */ + buffer_name = jabber_buffer_build_name (server->name, muc_name); + new_buffer = weechat_buffer_search (JABBER_PLUGIN_NAME, buffer_name); + if (new_buffer) + weechat_nicklist_remove_all (new_buffer); + else + { + new_buffer = weechat_buffer_new (buffer_name, + &jabber_input_data_cb, NULL, + &jabber_buffer_close_cb, NULL); + if (!new_buffer) + { + free (new_muc); + return NULL; + } + + weechat_buffer_set (new_buffer, "short_name", muc_name); + weechat_buffer_set (new_buffer, "localvar_set_nick", + jabber_server_get_local_name (server)); + weechat_buffer_set (new_buffer, "localvar_set_server", server->name); + weechat_buffer_set (new_buffer, "localvar_set_muc", muc_name); + + weechat_hook_signal_send ("logger_backlog", + WEECHAT_HOOK_SIGNAL_POINTER, new_buffer); + } + + if (muc_type == JABBER_MUC_TYPE_MUC) + { + weechat_buffer_set (new_buffer, "nicklist", "1"); + weechat_buffer_set (new_buffer, "nicklist_display_groups", "0"); + weechat_nicklist_add_group (new_buffer, NULL, JABBER_BUDDY_GROUP_OP, + "weechat.color.nicklist_group", 1); + weechat_nicklist_add_group (new_buffer, NULL, JABBER_BUDDY_GROUP_HALFOP, + "weechat.color.nicklist_group", 1); + weechat_nicklist_add_group (new_buffer, NULL, JABBER_BUDDY_GROUP_VOICE, + "weechat.color.nicklist_group", 1); + weechat_nicklist_add_group (new_buffer, NULL, JABBER_BUDDY_GROUP_CHANUSER, + "weechat.color.nicklist_group", 1); + weechat_nicklist_add_group (new_buffer, NULL, JABBER_BUDDY_GROUP_NORMAL, + "weechat.color.nicklist_group", 1); + } + + /* set highlights settings on MUC buffer */ + weechat_buffer_set (new_buffer, "highlight_words", + jabber_server_get_local_name (server)); + if (weechat_config_string (jabber_config_look_highlight_tags) + && weechat_config_string (jabber_config_look_highlight_tags)[0]) + { + weechat_buffer_set (new_buffer, "highlight_tags", + weechat_config_string (jabber_config_look_highlight_tags)); + } + + /* initialize new MUC */ + new_muc->type = muc_type; + new_muc->name = strdup (muc_name); + new_muc->topic = NULL; + new_muc->modes = NULL; + new_muc->limit = 0; + new_muc->key = NULL; + new_muc->away_message = NULL; + new_muc->nick_completion_reset = 0; + new_muc->buddies_count = 0; + new_muc->buddies = NULL; + new_muc->last_buddy = NULL; + new_muc->buddies_speaking[0] = NULL; + new_muc->buddies_speaking[1] = NULL; + new_muc->buddies_speaking_time = NULL; + new_muc->last_buddy_speaking_time = NULL; + new_muc->buffer = new_buffer; + new_muc->buffer_as_string = NULL; + + /* add new MUC to MUCs list */ + new_muc->prev_muc = server->last_muc; + new_muc->next_muc = NULL; + if (server->mucs) + (server->last_muc)->next_muc = new_muc; + else + server->mucs = new_muc; + server->last_muc = new_muc; + + if (switch_to_muc) + weechat_buffer_set (new_buffer, "display", "1"); + + /* all is ok, return address of new muc */ + return new_muc; +} + +/* + * jabber_muc_set_topic: set topic for a muc + */ + +void +jabber_muc_set_topic (struct t_jabber_muc *muc, const char *topic) +{ + if (muc->topic) + free (muc->topic); + + muc->topic = (topic) ? strdup (topic) : NULL; + weechat_buffer_set (muc->buffer, "title", muc->topic); +} + +/* + * jabber_muc_search: returns pointer on a muc with name + */ + +struct t_jabber_muc * +jabber_muc_search (struct t_jabber_server *server, const char *muc_name) +{ + struct t_jabber_muc *ptr_muc; + + if (!server || !muc_name) + return NULL; + + for (ptr_muc = server->mucs; ptr_muc; + ptr_muc = ptr_muc->next_muc) + { + if (weechat_strcasecmp (ptr_muc->name, muc_name) == 0) + return ptr_muc; + } + return NULL; +} + +/* + * jabber_muc_remove_away: remove away for all buddies in a MUC + */ + +void +jabber_muc_remove_away (struct t_jabber_muc *muc) +{ + struct t_jabber_buddy *ptr_buddy; + + if (muc->type == JABBER_MUC_TYPE_MUC) + { + for (ptr_buddy = muc->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + jabber_buddy_set (NULL, muc, ptr_buddy, 0, JABBER_BUDDY_AWAY); + } + } +} + +/* + * jabber_muc_set_away: set/unset away status for a MUC + */ + +void +jabber_muc_set_away (struct t_jabber_muc *muc, const char *buddy_name, + int is_away) +{ + struct t_jabber_buddy *ptr_buddy; + + if (muc->type == JABBER_MUC_TYPE_MUC) + { + ptr_buddy = jabber_buddy_search (NULL, muc, buddy_name); + if (ptr_buddy) + jabber_buddy_set_away (NULL, muc, ptr_buddy, is_away); + } +} + +/* + * jabber_muc_buddy_speaking_add: add a buddy speaking in a MUC + */ + +void +jabber_muc_buddy_speaking_add (struct t_jabber_muc *muc, const char *buddy_name, + int highlight) +{ + int size, to_remove, i; + + if (highlight < 0) + highlight = 0; + if (highlight > 1) + highlight = 1; + + if (!muc->buddies_speaking[highlight]) + muc->buddies_speaking[highlight] = weechat_list_new (); + + weechat_list_add (muc->buddies_speaking[highlight], buddy_name, + WEECHAT_LIST_POS_END); + + size = weechat_list_size (muc->buddies_speaking[highlight]); + if (size > JABBER_MUC_BUDDIES_SPEAKING_LIMIT) + { + to_remove = size - JABBER_MUC_BUDDIES_SPEAKING_LIMIT; + for (i = 0; i < to_remove; i++) + { + weechat_list_remove (muc->buddies_speaking[highlight], + weechat_list_get (muc->buddies_speaking[highlight], 0)); + } + } +} + +/* + * jabber_muc_buddy_speaking_rename: rename a buddy speaking in a MUC + */ + +void +jabber_muc_buddy_speaking_rename (struct t_jabber_muc *muc, + const char *old_nick, + const char *new_nick) +{ + struct t_weelist_item *ptr_item; + int i; + + for (i = 0; i < 2; i++) + { + if (muc->buddies_speaking[i]) + { + ptr_item = weechat_list_search (muc->buddies_speaking[i], old_nick); + if (ptr_item) + weechat_list_set (ptr_item, new_nick); + } + } +} + +/* + * jabber_muc_buddy_speaking_time_search: search a buddy speaking time in a MUC + */ + +struct t_jabber_muc_speaking * +jabber_muc_buddy_speaking_time_search (struct t_jabber_muc *muc, + const char *buddy_name, + int check_time) +{ + struct t_jabber_muc_speaking *ptr_buddy; + time_t time_limit; + + time_limit = time (NULL) - + (weechat_config_integer (jabber_config_look_smart_filter_delay) * 60); + + for (ptr_buddy = muc->buddies_speaking_time; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + if (strcmp (ptr_buddy->buddy, buddy_name) == 0) + { + if (check_time && (ptr_buddy->time_last_message < time_limit)) + return NULL; + return ptr_buddy; + } + } + + /* buddy speaking time not found */ + return NULL; +} + +/* + * jabber_muc_buddy_speaking_time_free: free a buddy speaking in a MUC + */ + +void +jabber_muc_buddy_speaking_time_free (struct t_jabber_muc *muc, + struct t_jabber_muc_speaking *buddy_speaking) +{ + /* free data */ + if (buddy_speaking->buddy) + free (buddy_speaking->buddy); + + /* remove buddy from list */ + if (buddy_speaking->prev_buddy) + (buddy_speaking->prev_buddy)->next_buddy = buddy_speaking->next_buddy; + if (buddy_speaking->next_buddy) + (buddy_speaking->next_buddy)->prev_buddy = buddy_speaking->prev_buddy; + if (muc->buddies_speaking_time == buddy_speaking) + muc->buddies_speaking_time = buddy_speaking->next_buddy; + if (muc->last_buddy_speaking_time == buddy_speaking) + muc->last_buddy_speaking_time = buddy_speaking->prev_buddy; + + free (buddy_speaking); +} + +/* + * jabber_muc_buddy_speaking_time_free_all: free all buddies speaking in a MUC + */ + +void +jabber_muc_buddy_speaking_time_free_all (struct t_jabber_muc *muc) +{ + while (muc->buddies_speaking_time) + { + jabber_muc_buddy_speaking_time_free (muc, + muc->buddies_speaking_time); + } +} + +/* + * jabber_muc_buddy_speaking_time_remove_old: remove old buddies speaking + */ + +void +jabber_muc_buddy_speaking_time_remove_old (struct t_jabber_muc *muc) +{ + time_t time_limit; + + time_limit = time (NULL) - + (weechat_config_integer (jabber_config_look_smart_filter_delay) * 60); + + while (muc->last_buddy_speaking_time) + { + if (muc->last_buddy_speaking_time->time_last_message >= time_limit) + break; + + jabber_muc_buddy_speaking_time_free (muc, + muc->last_buddy_speaking_time); + } +} + +/* + * jabber_muc_buddy_speaking_time_add: add a buddy speaking time in a MUC + */ + +void +jabber_muc_buddy_speaking_time_add (struct t_jabber_muc *muc, + const char *buddy_name, + time_t time_last_message) +{ + struct t_jabber_muc_speaking *ptr_buddy, *new_buddy; + + ptr_buddy = jabber_muc_buddy_speaking_time_search (muc, buddy_name, 0); + if (ptr_buddy) + jabber_muc_buddy_speaking_time_free (muc, ptr_buddy); + + new_buddy = malloc (sizeof (*new_buddy)); + if (new_buddy) + { + new_buddy->buddy = strdup (buddy_name); + new_buddy->time_last_message = time_last_message; + + /* insert buddy at beginning of list */ + new_buddy->prev_buddy = NULL; + new_buddy->next_buddy = muc->buddies_speaking_time; + if (muc->buddies_speaking_time) + muc->buddies_speaking_time->prev_buddy = new_buddy; + else + muc->last_buddy_speaking_time = new_buddy; + muc->buddies_speaking_time = new_buddy; + } +} + +/* + * jabber_muc_buddy_speaking_time_rename: rename a buddy speaking time in a MUC + */ + +void +jabber_muc_buddy_speaking_time_rename (struct t_jabber_muc *muc, + const char *old_buddy, + const char *new_buddy) +{ + struct t_jabber_muc_speaking *ptr_buddy; + + if (muc->buddies_speaking_time) + { + ptr_buddy = jabber_muc_buddy_speaking_time_search (muc, old_buddy, 0); + if (ptr_buddy) + { + free (ptr_buddy->buddy); + ptr_buddy->buddy = strdup (new_buddy); + } + } +} + +/* + * jabber_muc_free: free a muc and remove it from MUCs list + */ + +void +jabber_muc_free (struct t_jabber_server *server, struct t_jabber_muc *muc) +{ + struct t_jabber_muc *new_mucs; + + if (!server || !muc) + return; + + /* remove muc from MUCs list */ + if (server->last_muc == muc) + server->last_muc = muc->prev_muc; + if (muc->prev_muc) + { + (muc->prev_muc)->next_muc = muc->next_muc; + new_mucs = server->mucs; + } + else + new_mucs = muc->next_muc; + + if (muc->next_muc) + (muc->next_muc)->prev_muc = muc->prev_muc; + + /* free data */ + if (muc->name) + free (muc->name); + if (muc->topic) + free (muc->topic); + if (muc->modes) + free (muc->modes); + if (muc->key) + free (muc->key); + jabber_buddy_free_all (NULL, muc); + if (muc->away_message) + free (muc->away_message); + if (muc->buddies_speaking[0]) + weechat_list_free (muc->buddies_speaking[0]); + if (muc->buddies_speaking[1]) + weechat_list_free (muc->buddies_speaking[1]); + jabber_muc_buddy_speaking_time_free_all (muc); + if (muc->buffer_as_string) + free (muc->buffer_as_string); + + free (muc); + + server->mucs = new_mucs; +} + +/* + * jabber_muc_free_all: free all allocated MUCs for a server + */ + +void +jabber_muc_free_all (struct t_jabber_server *server) +{ + while (server->mucs) + { + jabber_muc_free (server, server->mucs); + } +} + +/* + * jabber_muc_add_to_infolist: add a muc in an infolist + * return 1 if ok, 0 if error + */ + +int +jabber_muc_add_to_infolist (struct t_infolist *infolist, + struct t_jabber_muc *muc) +{ + struct t_infolist_item *ptr_item; + struct t_weelist_item *ptr_list_item; + struct t_jabber_muc_speaking *ptr_buddy; + char option_name[64]; + int i, index; + + if (!infolist || !muc) + return 0; + + ptr_item = weechat_infolist_new_item (infolist); + if (!ptr_item) + return 0; + + if (!weechat_infolist_new_var_pointer (ptr_item, "buffer", muc->buffer)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "buffer_name", + (muc->buffer) ? + weechat_buffer_get_string (muc->buffer, "name") : "")) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "buffer_short_name", + (muc->buffer) ? + weechat_buffer_get_string (muc->buffer, "short_name") : "")) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "type", muc->type)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "name", muc->name)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "topic", muc->topic)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "modes", muc->modes)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "limit", muc->limit)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "key", muc->key)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "buddies_count", muc->buddies_count)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "away_message", muc->away_message)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "nick_completion_reset", muc->nick_completion_reset)) + return 0; + for (i = 0; i < 2; i++) + { + if (muc->buddies_speaking[i]) + { + index = 0; + for (ptr_list_item = weechat_list_get (muc->buddies_speaking[i], 0); + ptr_list_item; + ptr_list_item = weechat_list_next (ptr_list_item)) + { + snprintf (option_name, sizeof (option_name), + "buddy_speaking%d_%05d", i, index); + if (!weechat_infolist_new_var_string (ptr_item, option_name, + weechat_list_string (ptr_list_item))) + return 0; + index++; + } + } + } + if (muc->buddies_speaking_time) + { + i = 0; + for (ptr_buddy = muc->last_buddy_speaking_time; ptr_buddy; + ptr_buddy = ptr_buddy->prev_buddy) + { + snprintf (option_name, sizeof (option_name), + "buddy_speaking_time_buddy_%05d", i); + if (!weechat_infolist_new_var_string (ptr_item, option_name, + ptr_buddy->buddy)) + return 0; + snprintf (option_name, sizeof (option_name), + "buddy_speaking_time_time_%05d", i); + if (!weechat_infolist_new_var_time (ptr_item, option_name, + ptr_buddy->time_last_message)) + return 0; + i++; + } + } + + return 1; +} + +/* + * jabber_muc_print_log: print muc infos in log (usually for crash dump) + */ + +void +jabber_muc_print_log (struct t_jabber_muc *muc) +{ + struct t_weelist_item *ptr_item; + struct t_jabber_muc_speaking *ptr_buddy_speaking; + int i, index; + struct t_jabber_buddy *ptr_buddy; + + weechat_log_printf (""); + weechat_log_printf (" => muc %s (addr:0x%lx)]", muc->name, muc); + weechat_log_printf (" type . . . . . . . . . . : %d", muc->type); + weechat_log_printf (" topic. . . . . . . . . . : '%s'", muc->topic); + weechat_log_printf (" modes. . . . . . . . . . : '%s'", muc->modes); + weechat_log_printf (" limit. . . . . . . . . . : %d", muc->limit); + weechat_log_printf (" key. . . . . . . . . . . : '%s'", muc->key); + weechat_log_printf (" away_message . . . . . . : '%s'", muc->away_message); + weechat_log_printf (" nick_completion_reset. . : %d", muc->nick_completion_reset); + weechat_log_printf (" buddies_count. . . . . . : %d", muc->buddies_count); + weechat_log_printf (" buddies. . . . . . . . . : 0x%lx", muc->buddies); + weechat_log_printf (" last_buddy . . . . . . . : 0x%lx", muc->last_buddy); + weechat_log_printf (" buddies_speaking[0]. . . : 0x%lx", muc->buddies_speaking[0]); + weechat_log_printf (" buddies_speaking[1]. . . : 0x%lx", muc->buddies_speaking[1]); + weechat_log_printf (" buddies_speaking_time. . : 0x%lx", muc->buddies_speaking_time); + weechat_log_printf (" last_buddy_speaking_time.: 0x%lx", muc->last_buddy_speaking_time); + weechat_log_printf (" buffer . . . . . . . . . : 0x%lx", muc->buffer); + weechat_log_printf (" buffer_as_string . . . . : '%s'", muc->buffer_as_string); + weechat_log_printf (" prev_muc . . . . . . . . : 0x%lx", muc->prev_muc); + weechat_log_printf (" next_muc . . . . . . . . : 0x%lx", muc->next_muc); + for (i = 0; i < 2; i++) + { + if (muc->buddies_speaking[i]) + { + weechat_log_printf (""); + index = 0; + for (ptr_item = weechat_list_get (muc->buddies_speaking[i], 0); + ptr_item; ptr_item = weechat_list_next (ptr_item)) + { + weechat_log_printf (" buddy speaking[%d][%d]: '%s'", + i, index, weechat_list_string (ptr_item)); + index++; + } + } + } + if (muc->buddies_speaking_time) + { + weechat_log_printf (""); + for (ptr_buddy_speaking = muc->buddies_speaking_time; + ptr_buddy_speaking; + ptr_buddy_speaking = ptr_buddy_speaking->next_buddy) + { + weechat_log_printf (" buddy speaking time: '%s', time: %ld", + ptr_buddy_speaking->buddy, + ptr_buddy_speaking->time_last_message); + } + } + for (ptr_buddy = muc->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + jabber_buddy_print_log (ptr_buddy); + } +} diff --git a/src/plugins/jabber/jabber-muc.h b/src/plugins/jabber/jabber-muc.h new file mode 100644 index 000000000..4d0e81604 --- /dev/null +++ b/src/plugins/jabber/jabber-muc.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_MUC_H +#define __WEECHAT_JABBER_MUC_H 1 + +/* MUC types */ +#define JABBER_MUC_TYPE_UNKNOWN -1 +#define JABBER_MUC_TYPE_MUC 0 +#define JABBER_MUC_TYPE_PRIVATE 1 + +#define JABBER_MUC_BUDDIES_SPEAKING_LIMIT 128 + +struct t_jabber_server; + +struct t_jabber_muc_speaking +{ + char *buddy; /* buddy speaking */ + time_t time_last_message; /* time */ + struct t_jabber_muc_speaking *prev_buddy; /* pointer to previous buddy */ + struct t_jabber_muc_speaking *next_buddy; /* pointer to next buddy */ +}; + +struct t_jabber_muc +{ + int type; /* MUC type */ + char *name; /* name of MUC (exemple: "test") */ + char *topic; /* topic of MUC (host for pv) */ + char *modes; /* MUC modes */ + int limit; /* user limit (0 is limit not set) */ + char *key; /* MUC key (NULL if no key set) */ + char *away_message; /* to display away only once in pv */ + int nick_completion_reset; /* 1 for resetting nick completion */ + /* there was some join/part on chan */ + int buddies_count; /* # buddies in MUC (0 if pv) */ + struct t_jabber_buddy *buddies; /* buddies in MUC */ + struct t_jabber_buddy *last_buddy; /* last buddy in MUC */ + struct t_weelist *buddies_speaking[2]; /* for smart completion: first */ + /* list is buddy speaking, second is */ + /* speaking to me (highlight) */ + struct t_jabber_muc_speaking *buddies_speaking_time; /* for smart filter*/ + /* of join/quit messages */ + struct t_jabber_muc_speaking *last_buddy_speaking_time; + struct t_gui_buffer *buffer; /* buffer allocated for MUC */ + char *buffer_as_string; /* used to return buffer info */ + struct t_jabber_muc *prev_muc; /* link to previous MUC */ + struct t_jabber_muc *next_muc; /* link to next MUC */ +}; + +extern int jabber_muc_valid (struct t_jabber_server *server, + struct t_jabber_muc *muc); +extern struct t_jabber_muc *jabber_muc_new (struct t_jabber_server *server, + int muc_type, + const char *muc_name, + int switch_to_muc); +extern void jabber_muc_set_topic (struct t_jabber_muc *muc, + const char *topic); +extern void jabber_muc_free (struct t_jabber_server *server, + struct t_jabber_muc *muc); +extern void jabber_muc_free_all (struct t_jabber_server *server); +extern struct t_jabber_muc *jabber_muc_search (struct t_jabber_server *server, + const char *muc_name); +extern int jabber_muc_is_muc (const char *string); +extern void jabber_muc_remove_away (struct t_jabber_muc *muc); +extern void jabber_muc_check_away (struct t_jabber_server *server, + struct t_jabber_muc *muc, int force); +extern void jabber_muc_set_away (struct t_jabber_muc *muc, + const char *buddy_name, + int is_away); +extern void jabber_muc_buddy_speaking_add (struct t_jabber_muc *muc, + const char *buddy_name, + int highlight); +extern void jabber_muc_buddy_speaking_rename (struct t_jabber_muc *muc, + const char *old_buddy, + const char *new_buddy); +extern struct t_jabber_muc_speaking *jabber_muc_buddy_speaking_time_search (struct t_jabber_muc *muc, + const char *buddy_name, + int check_time); +extern void jabber_muc_buddy_speaking_time_remove_old (struct t_jabber_muc *muc); +extern void jabber_muc_buddy_speaking_time_add (struct t_jabber_muc *muc, + const char *buddy_name, + time_t time_last_message); +extern void jabber_muc_buddy_speaking_time_rename (struct t_jabber_muc *muc, + const char *old_buddy, + const char *new_buddy); +extern int jabber_muc_add_to_infolist (struct t_infolist *infolist, + struct t_jabber_muc *muc); +extern void jabber_muc_print_log (struct t_jabber_muc *muc); + +#endif /* jabber-muc.h */ diff --git a/src/plugins/jabber/jabber-server.c b/src/plugins/jabber/jabber-server.c new file mode 100644 index 000000000..859ce51dc --- /dev/null +++ b/src/plugins/jabber/jabber-server.c @@ -0,0 +1,1987 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber-server.c: connection and I/O communication with Jabber server */ + + +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <time.h> +#ifdef _WIN32 +#include <winsock.h> +#else +#include <sys/socket.h> +#include <sys/time.h> +#endif + +#ifdef HAVE_GNUTLS +#include <gnutls/gnutls.h> +#endif + +#include <iksemel.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-server.h" +#include "jabber-buddy.h" +#include "jabber-buffer.h" +#include "jabber-command.h" +#include "jabber-config.h" +#include "jabber-debug.h" +#include "jabber-muc.h" +#include "jabber-xmpp.h" + + +struct t_jabber_server *jabber_servers = NULL; +struct t_jabber_server *last_jabber_server = NULL; + +/* current server when there is one buffer for all servers */ +struct t_jabber_server *jabber_current_server = NULL; + +struct t_jabber_message *jabber_recv_msgq = NULL; +struct t_jabber_message *jabber_msgq_last_msg = NULL; + +ikstransport jabber_iks_transport = +{ + .abi_version = IKS_TRANSPORT_V1, + .connect = NULL, + .send = &jabber_server_iks_transport_send, + .recv = &jabber_server_iks_transport_recv, + .close = &jabber_server_iks_transport_close, + .connect_async = &jabber_server_iks_transport_connect_async, +}; + +char *jabber_server_option_string[JABBER_SERVER_NUM_OPTIONS] = +{ "username", "server", "proxy", "ipv6", "tls", "sasl", "resource", "password", + "local_alias", "autoconnect", "autoreconnect", "autoreconnect_delay", + "local_hostname", "command", "command_delay", "autojoin", "autorejoin" +}; + +char *jabber_server_option_default[JABBER_SERVER_NUM_OPTIONS] = +{ "", "", "", "off", "off", "on", "", "", "", "off", "on", "10", "", "", "0", + "", "off" +}; + + +/* + * jabber_server_valid: check if a server pointer exists + * return 1 if server exists + * 0 if server is not found + */ + +int +jabber_server_valid (struct t_jabber_server *server) +{ + struct t_jabber_server *ptr_server; + + if (!server) + return 0; + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (ptr_server == server) + return 1; + } + + /* server not found */ + return 0; +} + +/* + * jabber_server_search_option: search a server option name + * return index of option in array + * "jabber_server_option_string", or -1 if + * not found + */ + +int +jabber_server_search_option (const char *option_name) +{ + int i; + + if (!option_name) + return -1; + + for (i = 0; i < JABBER_SERVER_NUM_OPTIONS; i++) + { + if (weechat_strcasecmp (jabber_server_option_string[i], + option_name) == 0) + return i; + } + + /* server option not found */ + return -1; +} + +/* + * jabber_server_search: return pointer on a server with a name + */ + +struct t_jabber_server * +jabber_server_search (const char *server_name) +{ + struct t_jabber_server *ptr_server; + + if (!server_name) + return NULL; + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (strcmp (ptr_server->name, server_name) == 0) + return ptr_server; + } + + /* server not found */ + return NULL; +} + +/* + * jabber_server_get_muc_count: return number of MUCs for server + */ + +int +jabber_server_get_muc_count (struct t_jabber_server *server) +{ + int count; + struct t_jabber_muc *ptr_muc; + + count = 0; + for (ptr_muc = server->mucs; ptr_muc; ptr_muc = ptr_muc->next_muc) + { + if (ptr_muc->type == JABBER_MUC_TYPE_MUC) + count++; + } + return count; +} + +/* + * jabber_server_get_pv_count: return number of pv for server + */ + +int +jabber_server_get_pv_count (struct t_jabber_server *server) +{ + int count; + struct t_jabber_muc *ptr_muc; + + count = 0; + for (ptr_muc = server->mucs; ptr_muc; ptr_muc = ptr_muc->next_muc) + { + if (ptr_muc->type == JABBER_MUC_TYPE_PRIVATE) + count++; + } + return count; +} + +/* + * jabber_server_get_name_without_port: get name of server without port + * (ends before first '/' if found) + */ + +char * +jabber_server_get_name_without_port (const char *name) +{ + char *pos; + + if (!name) + return NULL; + + pos = strchr (name, '/'); + if (pos && (pos != name)) + return weechat_strndup (name, pos - name); + + return strdup (name); +} + +/* + * jabber_server_get_local_name: get local alias for server (if defined), + * otherwise return username + */ + +const char * +jabber_server_get_local_name (struct t_jabber_server *server) +{ + const char *local_alias; + + local_alias = JABBER_SERVER_OPTION_STRING(server, + JABBER_SERVER_OPTION_LOCAL_ALIAS); + if (local_alias && local_alias[0]) + return local_alias; + + /* fallback to username */ + return JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_USERNAME); +} + +/* + * jabber_server_set_server: set server address + */ + +void +jabber_server_set_server (struct t_jabber_server *server, + const char *address) +{ + char *pos, *error; + long number; + + /* free data */ + if (server->address) + { + free (server->address); + server->address = NULL; + } + server->port = JABBER_SERVER_DEFAULT_PORT; + + if (address && address[0]) + { + pos = strchr (address, '/'); + if (pos && (pos > address)) + { + server->address = weechat_strndup (address, pos - address); + pos++; + error = NULL; + number = strtol (pos, &error, 10); + if (error && !error[0]) + server->port = number; + } + else + server->address = strdup (address); + } +} + +/* + * jabber_server_buffer_set_highlight_words: set highlight words for buffer + * with all servers + */ + +void +jabber_server_buffer_set_highlight_words (struct t_gui_buffer *buffer) +{ + struct t_jabber_server *ptr_server; + int length; + const char *local_name; + char *words; + + length = 0; + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (ptr_server->is_connected) + { + local_name = jabber_server_get_local_name (ptr_server); + if (local_name && local_name[0]) + length += strlen (local_name) + 1; + } + } + words = malloc (length + 1); + if (words) + { + words[0] = '\0'; + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (ptr_server->is_connected) + { + local_name = jabber_server_get_local_name (ptr_server); + if (local_name && local_name[0]) + { + if (words[0]) + strcat (words, ","); + strcat (words, local_name); + } + } + } + weechat_buffer_set (buffer, "highlight_words", words); + free (words); + } +} + +/* + * jabber_server_alloc: allocate a new server and add it to the servers queue + */ + +struct t_jabber_server * +jabber_server_alloc (const char *name) +{ + struct t_jabber_server *new_server; + int i, length; + char *option_name; + + if (jabber_server_search (name)) + return NULL; + + /* alloc memory for new server */ + new_server = malloc (sizeof (*new_server)); + if (!new_server) + { + weechat_printf (NULL, + _("%s%s: error when allocating new server"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME); + return NULL; + } + + /* add new server to queue */ + new_server->prev_server = last_jabber_server; + new_server->next_server = NULL; + if (jabber_servers) + last_jabber_server->next_server = new_server; + else + jabber_servers = new_server; + last_jabber_server = new_server; + + /* set name */ + new_server->name = strdup (name); + + /* internal vars */ + new_server->temp_server = 0; + new_server->reloading_from_config = 0; + new_server->reloaded_from_config = 0; + new_server->address = NULL; + new_server->port = JABBER_SERVER_DEFAULT_PORT; + new_server->current_ip = NULL; + new_server->sock = -1; + new_server->iks_parser = NULL; + new_server->iks_id_string = NULL; + new_server->iks_id = NULL; + new_server->iks_server_name = NULL; + new_server->iks_password = NULL; + new_server->iks_filter = NULL; + new_server->iks_roster = NULL; + new_server->iks_features = 0; + new_server->iks_authorized = 0; + new_server->hook_connect = NULL; + new_server->hook_fd = NULL; + new_server->is_connected = 0; + new_server->tls_connected = 0; + new_server->reconnect_start = 0; + new_server->command_time = 0; + new_server->reconnect_join = 0; + new_server->disable_autojoin = 0; + new_server->is_away = 0; + new_server->away_message = NULL; + new_server->away_time = 0; + new_server->lag = 0; + new_server->lag_check_time.tv_sec = 0; + new_server->lag_check_time.tv_usec = 0; + new_server->lag_next_check = time (NULL) + + weechat_config_integer (jabber_config_network_lag_check); + new_server->buffer = NULL; + new_server->buffer_as_string = NULL; + new_server->buddies_count = 0; + new_server->buddies = NULL; + new_server->last_buddy = NULL; + new_server->mucs = NULL; + new_server->last_muc = NULL; + + /* create options with null value */ + for (i = 0; i < JABBER_SERVER_NUM_OPTIONS; i++) + { + length = strlen (new_server->name) + 1 + + strlen (jabber_server_option_string[i]) + 1; + option_name = malloc (length); + if (option_name) + { + snprintf (option_name, length, "%s.%s", + new_server->name, + jabber_server_option_string[i]); + new_server->options[i] = + jabber_config_server_new_option (jabber_config_file, + jabber_config_section_server, + i, + option_name, + NULL, + NULL, + 1, + &jabber_config_server_change_cb, + jabber_server_option_string[i]); + jabber_config_server_change_cb (jabber_server_option_string[i], + new_server->options[i]); + free (option_name); + } + } + + return new_server; +} + +/* + * jabber_server_close_connection: close server connection + */ + +void +jabber_server_close_connection (struct t_jabber_server *server) +{ + if (server->hook_fd) + { + weechat_unhook (server->hook_fd); + server->hook_fd = NULL; + } + + if (server->hook_connect) + { + weechat_unhook (server->hook_connect); + server->hook_connect = NULL; + } + else + { +#ifdef HAVE_GNUTLS + /* close TLS connection */ + //if ((server->sock != -1) && (server->tls_connected)) + //{ + // if (server->tls_connected) + // gnutls_bye (server->gnutls_sess, GNUTLS_SHUT_WR); + // if (server->tls_connected) + // gnutls_deinit (server->gnutls_sess); + //} +#endif + } + if (server->iks_parser) + { + iks_parser_delete (server->iks_parser); + server->iks_parser = NULL; + } + server->sock = -1; + if (server->iks_id_string) + { + free (server->iks_id_string); + server->iks_id_string = NULL; + } + server->iks_id = NULL; + if (server->iks_server_name) + { + free (server->iks_server_name); + server->iks_server_name = NULL; + } + if (server->iks_password) + { + free (server->iks_password); + server->iks_password = NULL; + } + if (server->iks_filter) + { + iks_filter_delete (server->iks_filter); + server->iks_filter = NULL; + } + server->iks_roster = NULL; + server->iks_features = 0; + server->iks_authorized = 0; + + /* remove buddies */ + jabber_buddy_free_all (server, NULL); + + /* server is now disconnected */ + server->is_connected = 0; + server->tls_connected = 0; + if (server->current_ip) + { + free (server->current_ip); + server->current_ip = NULL; + } +} + +/* + * jabber_server_reconnect_schedule: schedule reconnect for a server + */ + +void +jabber_server_reconnect_schedule (struct t_jabber_server *server) +{ + int delay; + + if (JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_AUTORECONNECT)) + { + server->reconnect_start = time (NULL); + delay = JABBER_SERVER_OPTION_INTEGER(server, JABBER_SERVER_OPTION_AUTORECONNECT_DELAY); + weechat_printf (server->buffer, + _("%s%s: reconnecting to server in %d %s"), + jabber_buffer_get_server_prefix (server, NULL), + JABBER_PLUGIN_NAME, + delay, + NG_("second", "seconds", delay)); + } + else + server->reconnect_start = 0; +} + +/* + * jabber_server_login: login to Jabber server + */ + +void +jabber_server_login (struct t_jabber_server *server) +{ + server->is_connected = 1; + + iks_send_header (server->iks_parser, server->iks_server_name); +} + +/* + * jabber_server_connect_cb: read connection status + */ + +int +jabber_server_connect_cb (void *arg_server, int status, const char *ip_address) +{ + struct t_jabber_server *server; + const char *proxy; + + server = (struct t_jabber_server *)arg_server; + + proxy = JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_PROXY); + + server->hook_connect = NULL; + + switch (status) + { + case WEECHAT_HOOK_CONNECT_OK: + /* login to server */ + if (server->current_ip) + free (server->current_ip); + server->current_ip = (ip_address) ? strdup (ip_address) : NULL; + weechat_printf (server->buffer, + _("%s%s: connected to %s (%s)"), + jabber_buffer_get_server_prefix (server, NULL), + JABBER_PLUGIN_NAME, + server->address, + (server->current_ip) ? server->current_ip : "?"); + server->hook_fd = weechat_hook_fd (server->sock, + 1, 0, 0, + &jabber_server_recv_cb, + server); + jabber_server_login (server); + break; + case WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND: + weechat_printf (server->buffer, + (proxy && proxy[0]) ? + _("%s%s: proxy address \"%s\" not found") : + _("%s%s: address \"%s\" not found"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME, + server->address); + jabber_server_close_connection (server); + jabber_server_reconnect_schedule (server); + break; + case WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND: + weechat_printf (server->buffer, + (proxy && proxy[0]) ? + _("%s%s: proxy IP address not found") : + _("%s%s: IP address not found"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME); + jabber_server_close_connection (server); + jabber_server_reconnect_schedule (server); + break; + case WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED: + weechat_printf (server->buffer, + (proxy && proxy[0]) ? + _("%s%s: proxy connection refused") : + _("%s%s: connection refused"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME); + jabber_server_close_connection (server); + jabber_server_reconnect_schedule (server); + break; + case WEECHAT_HOOK_CONNECT_PROXY_ERROR: + weechat_printf (server->buffer, + _("%s%s: proxy fails to establish " + "connection to server " + "(check username/password if used " + "and if server address/port is allowed by " + "proxy)"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME); + jabber_server_close_connection (server); + jabber_server_reconnect_schedule (server); + break; + case WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR: + weechat_printf (server->buffer, + _("%s%s: unable to set local hostname/IP"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME); + jabber_server_close_connection (server); + jabber_server_reconnect_schedule (server); + break; + case WEECHAT_HOOK_CONNECT_GNUTLS_INIT_ERROR: + weechat_printf (server->buffer, + _("%s%s: GnuTLS init error"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME); + jabber_server_close_connection (server); + jabber_server_reconnect_schedule (server); + break; + case WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR: + weechat_printf (server->buffer, + _("%s%s: GnuTLS handshake failed"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME); + jabber_server_close_connection (server); + jabber_server_reconnect_schedule (server); + break; + case WEECHAT_HOOK_CONNECT_MEMORY_ERROR: + weechat_printf (server->buffer, + _("%s%s: not enough memory"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME); + jabber_server_close_connection (server); + jabber_server_reconnect_schedule (server); + break; + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_server_set_buffer_title: set title for a server buffer + */ + +void +jabber_server_set_buffer_title (struct t_jabber_server *server) +{ + char *title; + int length; + + if (server && server->buffer) + { + if (server->is_connected) + { + length = 16 + strlen (server->address) + 16 + + ((server->current_ip) ? strlen (server->current_ip) : 16) + 1; + title = malloc (length); + if (title) + { + snprintf (title, length, "Jabber: %s/%d (%s)", + server->address, server->port, + (server->current_ip) ? server->current_ip : ""); + weechat_buffer_set (server->buffer, "title", title); + free (title); + } + } + else + { + weechat_buffer_set (server->buffer, "title", ""); + } + } +} + +/* + * jabber_server_create_buffer: create a buffer for a Jabber server + */ + +struct t_gui_buffer * +jabber_server_create_buffer (struct t_jabber_server *server, int all_servers) +{ + char buffer_name[256], charset_modifier[256]; + const char *local_name; + + if (all_servers) + { + snprintf (buffer_name, sizeof (buffer_name), + JABBER_BUFFER_ALL_SERVERS_NAME); + } + else + { + snprintf (buffer_name, sizeof (buffer_name), + "server.%s", server->name); + } + server->buffer = weechat_buffer_new (buffer_name, + NULL, NULL, + &jabber_buffer_close_cb, NULL); + if (!server->buffer) + return NULL; + + weechat_buffer_set (server->buffer, "short_name", + (weechat_config_boolean (jabber_config_look_one_server_buffer)) ? + JABBER_BUFFER_ALL_SERVERS_NAME : server->name); + weechat_buffer_set (server->buffer, "localvar_set_server", + (weechat_config_boolean (jabber_config_look_one_server_buffer)) ? + JABBER_BUFFER_ALL_SERVERS_NAME : server->name); + weechat_buffer_set (server->buffer, "localvar_set_muc", + (weechat_config_boolean (jabber_config_look_one_server_buffer)) ? + JABBER_BUFFER_ALL_SERVERS_NAME : server->name); + snprintf (charset_modifier, sizeof (charset_modifier), + "jabber.%s", server->name); + weechat_buffer_set (server->buffer, "localvar_set_charset_modifier", + charset_modifier); + + weechat_buffer_set (server->buffer, "nicklist", "1"); + weechat_buffer_set (server->buffer, "nicklist_display_groups", "0"); + + weechat_hook_signal_send ("logger_backlog", + WEECHAT_HOOK_SIGNAL_POINTER, server->buffer); + + /* set highlights settings on server buffer */ + local_name = jabber_server_get_local_name (server); + if (local_name && local_name[0]) + weechat_buffer_set (server->buffer, "highlight_words", local_name); + if (weechat_config_string (jabber_config_look_highlight_tags) + && weechat_config_string (jabber_config_look_highlight_tags)[0]) + { + weechat_buffer_set (server->buffer, "highlight_tags", + weechat_config_string (jabber_config_look_highlight_tags)); + } + + jabber_server_set_buffer_title (server); + + return server->buffer; +} + +/* + * jabber_server_set_current_server: set new current server (when all servers + * are in one buffer) + */ + +void +jabber_server_set_current_server (struct t_jabber_server *server) +{ + char charset_modifier[256]; + + jabber_current_server = server; + + jabber_server_set_buffer_title (jabber_current_server); + snprintf (charset_modifier, sizeof (charset_modifier), + "jabber.%s", jabber_current_server->name); + weechat_buffer_set (jabber_current_server->buffer, + "localvar_set_charset_modifier", + charset_modifier); + weechat_bar_item_update ("buffer_name"); + weechat_bar_item_update ("input_prompt"); +} + +/* + * jabber_server_iks_transport_connect_async: async connection to server + * (for iksemel lib) + */ + +int +jabber_server_iks_transport_connect_async (iksparser *parser, void **socketptr, + const char *server, + const char *server_name, + int port, void *notify_data, + iksAsyncNotify *notify_func) +{ + struct t_jabber_server *ptr_server; + int set, length; + char *option_name; + struct t_config_option *proxy_type, *proxy_ipv6, *proxy_address, *proxy_port; + const char *proxy, *str_proxy_type, *str_proxy_address; + + /* make C compiler happy */ + (void) parser; + (void) server_name; + (void) notify_func; + + ptr_server = (struct t_jabber_server *)notify_data; + + proxy_type = NULL; + proxy_ipv6 = NULL; + proxy_address = NULL; + proxy_port = NULL; + str_proxy_type = NULL; + str_proxy_address = NULL; + + proxy = JABBER_SERVER_OPTION_STRING(ptr_server, JABBER_SERVER_OPTION_PROXY); + if (proxy && proxy[0]) + { + length = 32 + strlen (proxy) + 1; + option_name = malloc (length); + if (!option_name) + { + weechat_printf (ptr_server->buffer, + _("%s%s: not enough memory"), + jabber_buffer_get_server_prefix (ptr_server, "error"), + JABBER_PLUGIN_NAME); + return 0; + } + snprintf (option_name, length, "weechat.proxy.%s.type", proxy); + proxy_type = weechat_config_get (option_name); + snprintf (option_name, length, "weechat.proxy.%s.ipv6", proxy); + proxy_ipv6 = weechat_config_get (option_name); + snprintf (option_name, length, "weechat.proxy.%s.address", proxy); + proxy_address = weechat_config_get (option_name); + snprintf (option_name, length, "weechat.proxy.%s.port", proxy); + proxy_port = weechat_config_get (option_name); + free (option_name); + if (!proxy_type || !proxy_address) + { + weechat_printf (ptr_server->buffer, + _("%s%s: proxy \"%s\" not found for server " + "\"%s\", cannot connect"), + jabber_buffer_get_server_prefix (ptr_server, "error"), + JABBER_PLUGIN_NAME, proxy, ptr_server->name); + return 0; + } + str_proxy_type = weechat_config_string (proxy_type); + str_proxy_address = weechat_config_string (proxy_address); + if (!str_proxy_type[0] || !proxy_ipv6 || !str_proxy_address[0] + || !proxy_port) + { + weechat_printf (ptr_server->buffer, + _("%s%s: missing proxy settings, check options " + "for proxy \"%s\""), + jabber_buffer_get_server_prefix (ptr_server, "error"), + JABBER_PLUGIN_NAME, proxy); + return 0; + } + } + + if (proxy_type) + { + weechat_printf (ptr_server->buffer, + _("%s%s: connecting to server %s/%d%s%s%s via %s " + "proxy %s/%d%s..."), + jabber_buffer_get_server_prefix (ptr_server, NULL), + JABBER_PLUGIN_NAME, + server, + port, + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_IPV6)) ? + " (IPv6)" : "", + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_TLS)) ? + " (TLS)" : "", + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_SASL)) ? + " (SASL)" : "", + str_proxy_type, + str_proxy_address, + weechat_config_integer (proxy_port), + (weechat_config_boolean (proxy_ipv6)) ? " (IPv6)" : ""); + weechat_log_printf (_("Connecting to server %s/%d%s%s%s via %s proxy " + "%s/%d%s..."), + server, + port, + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_IPV6)) ? + " (IPv6)" : "", + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_TLS)) ? + " (TLS)" : "", + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_SASL)) ? + " (SASL)" : "", + str_proxy_type, + str_proxy_address, + weechat_config_integer (proxy_port), + (weechat_config_boolean (proxy_ipv6)) ? " (IPv6)" : ""); + } + else + { + weechat_printf (ptr_server->buffer, + _("%s%s: connecting to server %s/%d%s%s%s..."), + jabber_buffer_get_server_prefix (ptr_server, NULL), + JABBER_PLUGIN_NAME, + server, + port, + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_IPV6)) ? + " (IPv6)" : "", + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_TLS)) ? + " (TLS)" : "", + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_SASL)) ? + " (SASL)" : ""); + weechat_log_printf (_("%s%s: connecting to server %s/%d%s%s%s..."), + "", + JABBER_PLUGIN_NAME, + server, + port, + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_IPV6)) ? + " (IPv6)" : "", + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_TLS)) ? + " (TLS)" : "", + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_SASL)) ? + " (SASL)" : ""); + } + + /* create socket and set options */ + if (proxy_type) + { + ptr_server->sock = socket ((weechat_config_integer (proxy_ipv6)) ? + AF_INET6 : AF_INET, + SOCK_STREAM, 0); + } + else + { + ptr_server->sock = socket ((JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_IPV6)) ? + AF_INET6 : AF_INET, + SOCK_STREAM, 0); + } + if (ptr_server->sock == -1) + { + weechat_printf (ptr_server->buffer, + _("%s%s: cannot create socket"), + jabber_buffer_get_server_prefix (ptr_server, "error"), + JABBER_PLUGIN_NAME); + return 0; + } + + /* set SO_REUSEADDR option for socket */ + set = 1; + if (setsockopt (ptr_server->sock, SOL_SOCKET, SO_REUSEADDR, + (void *) &set, sizeof (set)) == -1) + { + weechat_printf (ptr_server->buffer, + _("%s%s: cannot set socket option " + "\"SO_REUSEADDR\""), + jabber_buffer_get_server_prefix (ptr_server, "error"), + JABBER_PLUGIN_NAME); + } + + /* set SO_KEEPALIVE option for socket */ + set = 1; + if (setsockopt (ptr_server->sock, SOL_SOCKET, SO_KEEPALIVE, + (void *) &set, sizeof (set)) == -1) + { + weechat_printf (ptr_server->buffer, + _("%s%s: cannot set socket option " + "\"SO_KEEPALIVE\""), + jabber_buffer_get_server_prefix (ptr_server, "error"), + JABBER_PLUGIN_NAME); + } + + *socketptr = (void *) ptr_server->sock; + + /* init TLS if asked */ + ptr_server->tls_connected = 0; +#ifdef HAVE_GNUTLS + if (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_TLS)) + ptr_server->tls_connected = 1; +#endif + + ptr_server->hook_connect = weechat_hook_connect (proxy, + server, + port, + ptr_server->sock, + JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_IPV6), +#ifdef HAVE_GNUTLS + //(ptr_server->tls_connected) ? &ptr_server->gnutls_sess : NULL, + NULL, +#else + NULL, +#endif + JABBER_SERVER_OPTION_STRING(ptr_server, JABBER_SERVER_OPTION_LOCAL_HOSTNAME), + &jabber_server_connect_cb, + ptr_server); + + /* send signal "jabber_server_connecting" with server name */ + weechat_hook_signal_send ("jabber_server_connecting", + WEECHAT_HOOK_SIGNAL_STRING, ptr_server->name); + + return IKS_OK; +} + +/* + * jabber_server_iks_transport_send: send data to server (for iksemel lib) + */ + +int +jabber_server_iks_transport_send (void *socket, const char *data, size_t len) +{ + if (send ((int) socket, data, len, 0) == -1) + return IKS_NET_RWERR; + + return IKS_OK; +} + +/* + * jabber_server_iks_transport_recv: recv data from server (for iksemel lib) + */ + +int +jabber_server_iks_transport_recv (void *socket, char *buffer, size_t buf_len, + int timeout) +{ + int sock; + fd_set fds; + struct timeval tv; + int len; + + /* make C compiler happy */ + (void) timeout; + + tv.tv_sec = 0; + tv.tv_usec = 0; + + sock = (int) socket; + FD_ZERO (&fds); + FD_SET (sock, &fds); + if (select (sock + 1, &fds, NULL, NULL, &tv) > 0) + { + len = recv (sock, buffer, buf_len, 0); + if (len > 0) + return len; + else if (len <= 0) + return -1; + } + + return 0; +} + +/* + * jabber_server_iks_transport_close: close connection with server + * (for iksemel lib) + */ + +void +jabber_server_iks_transport_close (void *socket) +{ + int sock = (int)socket; + +#ifdef _WIN32 + closesocket (sock); +#else + close (sock); +#endif +} + +/* + * jabber_server_connect: connect to a Jabber server + * Return: 1 if ok + * 0 if error + */ + +int +jabber_server_connect (struct t_jabber_server *server) +{ + int length; + char charset_modifier[256]; + const char *username, *resource, *password; + + username = JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_USERNAME); + resource = JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_RESOURCE); + if (!username || !username[0] || !server->address || !server->address[0]) + { + weechat_printf (server->buffer, + _("%s%s: username or server not defined for server " + "\"%s\", cannot connect"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME, server->name); + return 0; + } + + if (!server->buffer) + { + if (weechat_config_boolean (jabber_config_look_one_server_buffer) + && jabber_buffer_servers) + { + server->buffer = jabber_buffer_servers; + jabber_server_set_buffer_title (server); + } + else + { + if (!jabber_server_create_buffer (server, + weechat_config_boolean (jabber_config_look_one_server_buffer))) + return 0; + } + + if (weechat_config_boolean (jabber_config_look_one_server_buffer)) + { + jabber_current_server = server; + if (!jabber_buffer_servers) + jabber_buffer_servers = server->buffer; + + snprintf (charset_modifier, sizeof (charset_modifier), + "jabber.%s", jabber_current_server->name); + weechat_buffer_set (jabber_buffer_servers, + "localvar_set_charset_modifier", + charset_modifier); + } + + weechat_buffer_set (server->buffer, "display", "1"); + + weechat_bar_item_update ("buffer_name"); + + weechat_buffer_set (server->buffer, "key_bind_meta-s", + "/command jabber /jabber switch"); + } + + if (!server->address) + { + weechat_printf (server->buffer, + _("%s%s: hostname/IP not defined for server \"%s\", " + "cannot connect"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME, server->name); + return 0; + } + +#ifndef HAVE_GNUTLS + //if (JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_TLS)) + //{ + // weechat_printf (server->buffer, + // _("%s%s: cannot connect with TLS because WeeChat " + // "was not built with GnuTLS support"), + // jabber_buffer_get_server_prefix (server, "error"), + // JABBER_PLUGIN_NAME); + // return 0; + //} +#endif + + if (JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_TLS) + && !iks_has_tls ()) + { + weechat_printf (server->buffer, + _("%s%s: cannot connect with TLS because iksemel " + "library was not built with GnuTLS support"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME); + return 0; + } + + /* close connection if opened */ + jabber_server_close_connection (server); + + /* build jabber ID */ + length = strlen (username) + 1 + strlen (server->address) + 1 + + strlen ((resource && resource[0]) ? resource : JABBER_SERVER_DEFAULT_RESOURCE) + 1; + server->iks_id_string = malloc (length); + if (!server->iks_id_string) + { + weechat_printf (server->buffer, + _("%s%s: not enough memory"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME); + return 0; + } + snprintf (server->iks_id_string, length, "%s@%s/%s", + username, server->address, + (resource && resource[0]) ? + resource : JABBER_SERVER_DEFAULT_RESOURCE); + server->iks_parser = iks_stream_new (IKS_NS_CLIENT, server, + &jabber_xmpp_iks_stream_hook); + if (!server->iks_parser) + { + weechat_printf (server->buffer, + _("%s%s: failed to create stream parser"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME); + return 0; + } + server->iks_id = iks_id_new (iks_parser_stack (server->iks_parser), + server->iks_id_string); + if (!server->iks_id) + { + iks_parser_delete (server->iks_parser); + server->iks_parser = NULL; + free (server->iks_id_string); + server->iks_id_string = NULL; + weechat_printf (server->buffer, + _("%s%s: failed to create id"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME); + return 0; + } + server->iks_server_name = strdup (server->address); + password = JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_PASSWORD); + server->iks_password = strdup ((password) ? password : ""); + iks_set_log_hook (server->iks_parser, &jabber_xmpp_iks_log); + server->iks_filter = iks_filter_new (); + iks_filter_add_rule (server->iks_filter, + &jabber_xmpp_iks_result, server, + IKS_RULE_TYPE, IKS_PAK_IQ, + IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, + IKS_RULE_ID, "auth", + IKS_RULE_DONE); + iks_filter_add_rule (server->iks_filter, + &jabber_xmpp_iks_error, server, + IKS_RULE_TYPE, IKS_PAK_IQ, + IKS_RULE_SUBTYPE, IKS_TYPE_ERROR, + IKS_RULE_ID, "auth", + IKS_RULE_DONE); + iks_filter_add_rule (server->iks_filter, + &jabber_xmpp_iks_roster, server, + IKS_RULE_TYPE, IKS_PAK_IQ, + IKS_RULE_SUBTYPE, IKS_TYPE_RESULT, + IKS_RULE_ID, "roster", + IKS_RULE_DONE); + iks_connect_async_with (server->iks_parser, server->address, server->port, + server->iks_server_name, &jabber_iks_transport, + server, NULL); + + return 1; +} + +/* + * jabber_server_reconnect: reconnect to a server (after disconnection) + */ + +void +jabber_server_reconnect (struct t_jabber_server *server) +{ + weechat_printf (server->buffer, + _("%s%s: reconnecting to server..."), + jabber_buffer_get_server_prefix (server, NULL), + JABBER_PLUGIN_NAME); + server->reconnect_start = 0; + + if (jabber_server_connect (server)) + server->reconnect_join = 1; + else + jabber_server_reconnect_schedule (server); +} + +/* + * jabber_server_auto_connect: auto-connect to servers (called at startup) + */ + +void +jabber_server_auto_connect () +{ + struct t_jabber_server *ptr_server; + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + if (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_AUTOCONNECT)) + { + if (!jabber_server_connect (ptr_server)) + jabber_server_reconnect_schedule (ptr_server); + } + } +} + +/* + * jabber_server_disconnect: disconnect from a Jabber server + */ + +void +jabber_server_disconnect (struct t_jabber_server *server, int reconnect) +{ + struct t_jabber_muc *ptr_muc; + + if (server->is_connected) + { + /* remove all buddies and write disconnection message on each + MUC/private buffer */ + for (ptr_muc = server->mucs; ptr_muc; ptr_muc = ptr_muc->next_muc) + { + jabber_buddy_free_all (NULL, ptr_muc); + weechat_printf (ptr_muc->buffer, + _("%s%s: disconnected from server"), + "", + JABBER_PLUGIN_NAME); + } + } + + jabber_server_close_connection (server); + + if (server->buffer) + { + weechat_printf (server->buffer, + _("%s%s: disconnected from server"), + jabber_buffer_get_server_prefix (server, NULL), + JABBER_PLUGIN_NAME); + } + + server->is_away = 0; + server->away_time = 0; + server->lag = 0; + server->lag_check_time.tv_sec = 0; + server->lag_check_time.tv_usec = 0; + server->lag_next_check = time (NULL) + + weechat_config_integer (jabber_config_network_lag_check); + + if (reconnect + && JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_AUTORECONNECT)) + jabber_server_reconnect_schedule (server); + else + server->reconnect_start = 0; + + jabber_server_set_buffer_title (server); + + /* send signal "jabber_server_disconnected" with server name */ + weechat_hook_signal_send ("jabber_server_disconnected", + WEECHAT_HOOK_SIGNAL_STRING, server->name); +} + +/* + * jabber_server_disconnect_all: disconnect from all jabber servers + */ + +void +jabber_server_disconnect_all () +{ + struct t_jabber_server *ptr_server; + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + jabber_server_disconnect (ptr_server, 0); + } +} + +/* + * jabber_server_free_data: free server data + */ + +void +jabber_server_free_data (struct t_jabber_server *server) +{ + int i; + + if (!server) + return; + + /* free data */ + for (i = 0; i < JABBER_SERVER_NUM_OPTIONS; i++) + { + if (server->options[i]) + weechat_config_option_free (server->options[i]); + } + if (server->address) + free (server->address); + if (server->current_ip) + free (server->current_ip); + if (server->iks_parser) + iks_parser_delete (server->iks_parser); + if (server->iks_id_string) + free (server->iks_id_string); + if (server->iks_server_name) + free (server->iks_server_name); + if (server->iks_password) + free (server->iks_password); + if (server->iks_filter) + iks_filter_delete (server->iks_filter); + if (server->away_message) + free (server->away_message); + if (server->mucs) + jabber_muc_free_all (server); + if (server->buddies) + jabber_buddy_free_all (server, NULL); + if (server->buffer_as_string) + free (server->buffer_as_string); +} + +/* + * jabber_server_free: free a server and remove it from servers queue + */ + +void +jabber_server_free (struct t_jabber_server *server) +{ + struct t_jabber_server *new_jabber_servers; + + if (!server) + return; + + /* close all MUCs/privates */ + jabber_muc_free_all (server); + + /* remove server from queue */ + if (last_jabber_server == server) + last_jabber_server = server->prev_server; + if (server->prev_server) + { + (server->prev_server)->next_server = server->next_server; + new_jabber_servers = jabber_servers; + } + else + new_jabber_servers = server->next_server; + + if (server->next_server) + (server->next_server)->prev_server = server->prev_server; + + jabber_server_free_data (server); + free (server); + jabber_servers = new_jabber_servers; +} + +/* + * jabber_server_free_all: free all allocated servers + */ + +void +jabber_server_free_all () +{ + /* for each server in memory, remove it */ + while (jabber_servers) + { + jabber_server_free (jabber_servers); + } +} + +/* + * jabber_server_copy: copy a server + * return: pointer to new server, NULL if error + */ + +struct t_jabber_server * +jabber_server_copy (struct t_jabber_server *server, const char *new_name) +{ + struct t_jabber_server *new_server; + struct t_infolist *infolist; + char *mask, *pos; + const char *option_name; + int length, index_option; + + /* check if another server exists with this name */ + if (jabber_server_search (new_name)) + return NULL; + + new_server = jabber_server_alloc (new_name); + if (new_server) + { + /* duplicate options */ + length = 32 + strlen (server->name) + 1; + mask = malloc (length); + if (!mask) + return 0; + snprintf (mask, length, "jabber.server.%s.*", server->name); + infolist = weechat_infolist_get ("option", NULL, mask); + free (mask); + while (weechat_infolist_next (infolist)) + { + if (!weechat_infolist_integer (infolist, "value_is_null")) + { + option_name = weechat_infolist_string (infolist, "option_name"); + pos = strrchr (option_name, '.'); + if (pos) + { + index_option = jabber_server_search_option (pos + 1); + if (index_option >= 0) + { + weechat_config_option_set (new_server->options[index_option], + weechat_infolist_string (infolist, "value"), + 1); + } + } + } + } + } + + return new_server; +} + +/* + * jabber_server_rename: rename server (internal name) + * return: 1 if ok, 0 if error + */ + +int +jabber_server_rename (struct t_jabber_server *server, + const char *new_server_name) +{ + int length; + char *mask, *pos_option, *new_option_name, *buffer_name; + const char *option_name; + struct t_infolist *infolist; + struct t_config_option *ptr_option; + //struct t_jabber_channel *ptr_channel; + + /* check if another server exists with this name */ + if (jabber_server_search (new_server_name)) + return 0; + + /* rename options */ + length = 32 + strlen (server->name) + 1; + mask = malloc (length); + if (!mask) + return 0; + snprintf (mask, length, "jabber.server.%s.*", server->name); + infolist = weechat_infolist_get ("option", NULL, mask); + free (mask); + while (weechat_infolist_next (infolist)) + { + weechat_config_search_with_string (weechat_infolist_string (infolist, + "full_name"), + NULL, NULL, &ptr_option, + NULL); + if (ptr_option) + { + option_name = weechat_infolist_string (infolist, "option_name"); + if (option_name) + { + pos_option = strrchr (option_name, '.'); + if (pos_option) + { + pos_option++; + length = strlen (new_server_name) + 1 + strlen (pos_option) + 1; + new_option_name = malloc (length); + if (new_option_name) + { + snprintf (new_option_name, length, + "%s.%s", new_server_name, pos_option); + weechat_config_option_rename (ptr_option, new_option_name); + free (new_option_name); + } + } + } + } + } + weechat_infolist_free (infolist); + + /* rename server */ + if (server->name) + free (server->name); + server->name = strdup (new_server_name); + + /* change name for buffers with this server */ + /* + for (ptr_channel = server->channels; ptr_channel; + ptr_channel = ptr_channel->next_channel) + { + if (ptr_channel->buffer) + { + buffer_name = jabber_buffer_build_name (server->name, ptr_channel->name); + weechat_buffer_set (ptr_channel->buffer, "name", buffer_name); + } + } + */ + if (server->buffer) + { + buffer_name = jabber_buffer_build_name (server->name, NULL); + weechat_buffer_set (server->buffer, "name", buffer_name); + } + + return 1; +} + +/* + * jabber_server_send_signal: send a signal for a Jabber message (received or sent) + */ + +void +jabber_server_send_signal (struct t_jabber_server *server, const char *signal, + const char *command, const char *full_message) +{ + int length; + char *str_signal; + + length = strlen (server->name) + 1 + strlen (signal) + 1 + strlen (command) + 1; + str_signal = malloc (length); + if (str_signal) + { + snprintf (str_signal, length, + "%s,%s_%s", server->name, signal, command); + weechat_hook_signal_send (str_signal, WEECHAT_HOOK_SIGNAL_STRING, + (void *)full_message); + free (str_signal); + } +} + +/* + * jabber_server_recv_cb: receive data from a jabber server + */ + +int +jabber_server_recv_cb (void *arg_server) +{ + struct t_jabber_server *server; + + server = (struct t_jabber_server *)arg_server; + + if (!server) + return WEECHAT_RC_ERROR; + + iks_recv (server->iks_parser, 0); + + return WEECHAT_RC_OK; +} + +/* + * jabber_server_timer_cb: timer called each second to perform some operations + * on servers + */ + +int +jabber_server_timer_cb (void *data) +{ + struct t_jabber_server *ptr_server; + time_t new_time; + //static struct timeval tv; + //int diff; + + /* make C compiler happy */ + (void) data; + + new_time = time (NULL); + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + /* check if reconnection is pending */ + if ((!ptr_server->is_connected) + && (ptr_server->reconnect_start > 0) + && (new_time >= (ptr_server->reconnect_start + + JABBER_SERVER_OPTION_INTEGER(ptr_server, JABBER_SERVER_OPTION_AUTORECONNECT_DELAY)))) + jabber_server_reconnect (ptr_server); + else + { + if (ptr_server->is_connected) + { + /* check for lag */ + //if ((ptr_server->lag_check_time.tv_sec == 0) + // && (new_time >= ptr_server->lag_next_check)) + //{ + // jabber_server_sendf (ptr_server, "PING %s", + // ptr_server->addresses_array[ptr_server->index_current_address]); + // gettimeofday (&(ptr_server->lag_check_time), NULL); + //} + + /* check if it's time to autojoin channels (after command delay) */ + //if ((ptr_server->command_time != 0) + // && (new_time >= ptr_server->command_time + + // JABBER_SERVER_OPTION_INTEGER(ptr_server, JABBER_SERVER_OPTION_COMMAND_DELAY))) + //{ + // jabber_server_autojoin_channels (ptr_server); + // ptr_server->command_time = 0; + //} + + /* lag timeout => disconnect */ + //if ((ptr_server->lag_check_time.tv_sec != 0) + // && (weechat_config_integer (jabber_config_network_lag_disconnect) > 0)) + //{ + // gettimeofday (&tv, NULL); + // diff = (int) weechat_timeval_diff (&(ptr_server->lag_check_time), + // &tv); + // if (diff / 1000 > weechat_config_integer (jabber_config_network_lag_disconnect) * 60) + // { + // weechat_printf (ptr_server->buffer, + // _("%s%s: lag is high, " + // "disconnecting from " + // "server..."), + // jabber_buffer_get_server_prefix (ptr_server, + // NULL), + // JABBER_PLUGIN_NAME); + // jabber_server_disconnect (ptr_server, 1); + // } + //} + } + } + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_server_add_to_infolist: add a server in an infolist + * return 1 if ok, 0 if error + */ + +int +jabber_server_add_to_infolist (struct t_infolist *infolist, + struct t_jabber_server *server) +{ + struct t_infolist_item *ptr_item; + + if (!infolist || !server) + return 0; + + ptr_item = weechat_infolist_new_item (infolist); + if (!ptr_item) + return 0; + + if (!weechat_infolist_new_var_string (ptr_item, "name", server->name)) + return 0; + if (!weechat_infolist_new_var_pointer (ptr_item, "buffer", server->buffer)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "buffer_name", + (server->buffer) ? + weechat_buffer_get_string (server->buffer, "name") : "")) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "buffer_short_name", + (server->buffer) ? + weechat_buffer_get_string (server->buffer, "short_name") : "")) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "selected", + (weechat_config_boolean (jabber_config_look_one_server_buffer) + && (jabber_current_server != server)) ? + 0 : 1)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "username", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_USERNAME))) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "server", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_SERVER))) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "proxy", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_PROXY))) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "ipv6", + JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_IPV6))) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "tls", + JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_TLS))) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "sasl", + JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_SASL))) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "resource", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_RESOURCE))) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "password", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_PASSWORD))) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "local_alias", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_LOCAL_ALIAS))) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "autoconnect", + JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_AUTOCONNECT))) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "autoreconnect", + JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_AUTORECONNECT))) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "autoreconnect_delay", + JABBER_SERVER_OPTION_INTEGER(server, JABBER_SERVER_OPTION_AUTORECONNECT_DELAY))) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "local_hostname", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_LOCAL_HOSTNAME))) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "command", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_COMMAND))) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "command_delay", + JABBER_SERVER_OPTION_INTEGER(server, JABBER_SERVER_OPTION_COMMAND_DELAY))) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "autojoin", + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_AUTOJOIN))) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "autorejoin", + JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_AUTOREJOIN))) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "temp_server", server->temp_server)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "address", server->address)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "port", server->port)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "current_ip", server->current_ip)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "sock", server->sock)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "iks_id_string", server->iks_id_string)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "iks_server_name", server->iks_server_name)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "iks_password", server->iks_password)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "iks_features", server->iks_features)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "iks_authorized", server->iks_authorized)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "is_connected", server->is_connected)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "tls_connected", server->tls_connected)) + return 0; + if (!weechat_infolist_new_var_time (ptr_item, "reconnect_start", server->reconnect_start)) + return 0; + if (!weechat_infolist_new_var_time (ptr_item, "command_time", server->command_time)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "reconnect_join", server->reconnect_join)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "disable_autojoin", server->disable_autojoin)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "is_away", server->is_away)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "away_message", server->away_message)) + return 0; + if (!weechat_infolist_new_var_time (ptr_item, "away_time", server->away_time)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "lag", server->lag)) + return 0; + if (!weechat_infolist_new_var_buffer (ptr_item, "lag_check_time", &(server->lag_check_time), sizeof (struct timeval))) + return 0; + if (!weechat_infolist_new_var_time (ptr_item, "lag_next_check", server->lag_next_check)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "buddies_count", server->buddies_count)) + return 0; + + return 1; +} + +/* + * jabber_server_print_log: print server infos in log (usually for crash dump) + */ + +void +jabber_server_print_log () +{ + struct t_jabber_server *ptr_server; + struct t_jabber_buddy *ptr_buddy; + struct t_jabber_muc *ptr_muc; + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + weechat_log_printf (""); + weechat_log_printf ("[server %s (addr:0x%lx)]", ptr_server->name, ptr_server); + + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_USERNAME])) + weechat_log_printf (" username . . . . . . : null ('%s')", + JABBER_SERVER_OPTION_STRING(ptr_server, JABBER_SERVER_OPTION_USERNAME)); + else + weechat_log_printf (" username . . . . . . : '%s'", + weechat_config_string (ptr_server->options[JABBER_SERVER_OPTION_USERNAME])); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_SERVER])) + weechat_log_printf (" server . . . . . . . : null ('%s')", + JABBER_SERVER_OPTION_STRING(ptr_server, JABBER_SERVER_OPTION_SERVER)); + else + weechat_log_printf (" server . . . . . . . : '%s'", + weechat_config_string (ptr_server->options[JABBER_SERVER_OPTION_SERVER])); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_PROXY])) + weechat_log_printf (" proxy. . . . . . . . : null ('%s')", + JABBER_SERVER_OPTION_STRING(ptr_server, JABBER_SERVER_OPTION_PROXY)); + else + weechat_log_printf (" proxy. . . . . . . . : '%s'", + weechat_config_string (ptr_server->options[JABBER_SERVER_OPTION_PROXY])); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_IPV6])) + weechat_log_printf (" ipv6 . . . . . . . . : null (%s)", + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_IPV6)) ? + "on" : "off"); + else + weechat_log_printf (" ipv6 . . . . . . . . : %s", + weechat_config_boolean (ptr_server->options[JABBER_SERVER_OPTION_IPV6]) ? + "on" : "off"); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_TLS])) + weechat_log_printf (" tls. . . . . . . . . : null (%s)", + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_TLS)) ? + "on" : "off"); + else + weechat_log_printf (" tls. . . . . . . . . : %s", + weechat_config_boolean (ptr_server->options[JABBER_SERVER_OPTION_TLS]) ? + "on" : "off"); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_SASL])) + weechat_log_printf (" sasl . . . . . . . . : null (%s)", + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_SASL)) ? + "on" : "off"); + else + weechat_log_printf (" sasl . . . . . . . . : %s", + weechat_config_boolean (ptr_server->options[JABBER_SERVER_OPTION_SASL]) ? + "on" : "off"); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_RESOURCE])) + weechat_log_printf (" resource . . . . . . : null ('%s')", + JABBER_SERVER_OPTION_STRING(ptr_server, JABBER_SERVER_OPTION_RESOURCE)); + else + weechat_log_printf (" resource . . . . . . : '%s'", + weechat_config_string (ptr_server->options[JABBER_SERVER_OPTION_RESOURCE])); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_PASSWORD])) + weechat_log_printf (" password . . . . . . : null"); + else + weechat_log_printf (" password . . . . . . : (hidden)"); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_LOCAL_ALIAS])) + weechat_log_printf (" local_alias. . . . . : null ('%s')", + JABBER_SERVER_OPTION_STRING(ptr_server, JABBER_SERVER_OPTION_LOCAL_ALIAS)); + else + weechat_log_printf (" local_alias. . . . . : '%s'", + weechat_config_string (ptr_server->options[JABBER_SERVER_OPTION_LOCAL_ALIAS])); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_AUTOCONNECT])) + weechat_log_printf (" autoconnect. . . . . : null (%s)", + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_AUTOCONNECT)) ? + "on" : "off"); + else + weechat_log_printf (" autoconnect. . . . . : %s", + weechat_config_boolean (ptr_server->options[JABBER_SERVER_OPTION_AUTOCONNECT]) ? + "on" : "off"); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_AUTORECONNECT])) + weechat_log_printf (" autoreconnect. . . . : null (%s)", + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_AUTORECONNECT)) ? + "on" : "off"); + else + weechat_log_printf (" autoreconnect. . . . : %s", + weechat_config_boolean (ptr_server->options[JABBER_SERVER_OPTION_AUTORECONNECT]) ? + "on" : "off"); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_AUTORECONNECT_DELAY])) + weechat_log_printf (" autoreconnect_delay. : null (%d)", + JABBER_SERVER_OPTION_INTEGER(ptr_server, JABBER_SERVER_OPTION_AUTORECONNECT_DELAY)); + else + weechat_log_printf (" autoreconnect_delay. : %d", + weechat_config_integer (ptr_server->options[JABBER_SERVER_OPTION_AUTORECONNECT_DELAY])); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_LOCAL_HOSTNAME])) + weechat_log_printf (" local_hostname . . . : null ('%s')", + JABBER_SERVER_OPTION_STRING(ptr_server, JABBER_SERVER_OPTION_LOCAL_HOSTNAME)); + else + weechat_log_printf (" local_hostname . . . : '%s'", + weechat_config_string (ptr_server->options[JABBER_SERVER_OPTION_LOCAL_HOSTNAME])); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_COMMAND])) + weechat_log_printf (" command. . . . . . . : null"); + else + weechat_log_printf (" command. . . . . . . : (hidden)"); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_COMMAND_DELAY])) + weechat_log_printf (" command_delay. . . . : null (%d)", + JABBER_SERVER_OPTION_INTEGER(ptr_server, JABBER_SERVER_OPTION_COMMAND_DELAY)); + else + weechat_log_printf (" command_delay. . . . : %d", + weechat_config_integer (ptr_server->options[JABBER_SERVER_OPTION_COMMAND_DELAY])); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_AUTOJOIN])) + weechat_log_printf (" autojoin . . . . . . : null ('%s')", + JABBER_SERVER_OPTION_STRING(ptr_server, JABBER_SERVER_OPTION_AUTOJOIN)); + else + weechat_log_printf (" autojoin . . . . . . : '%s'", + weechat_config_string (ptr_server->options[JABBER_SERVER_OPTION_AUTOJOIN])); + if (weechat_config_option_is_null (ptr_server->options[JABBER_SERVER_OPTION_AUTOREJOIN])) + weechat_log_printf (" autorejoin . . . . . : null (%s)", + (JABBER_SERVER_OPTION_BOOLEAN(ptr_server, JABBER_SERVER_OPTION_AUTOREJOIN)) ? + "on" : "off"); + else + weechat_log_printf (" autorejoin . . . . . : %s", + weechat_config_boolean (ptr_server->options[JABBER_SERVER_OPTION_AUTOREJOIN]) ? + "on" : "off"); + weechat_log_printf (" temp_server. . . . . : %d", ptr_server->temp_server); + weechat_log_printf (" reloading_from_config: %d", ptr_server->reloaded_from_config); + weechat_log_printf (" reloaded_from_config : %d", ptr_server->reloaded_from_config); + weechat_log_printf (" address. . . . . . . : '%s'", ptr_server->address); + weechat_log_printf (" port . . . . . . . . : %d", ptr_server->port); + weechat_log_printf (" current_ip . . . . . : '%s'", ptr_server->current_ip); + weechat_log_printf (" sock . . . . . . . . : %d", ptr_server->sock); + weechat_log_printf (" iks_parser . . . . . : 0x%lx", ptr_server->iks_parser); + weechat_log_printf (" iks_id_string. . . . : '%s'", ptr_server->iks_id_string); + weechat_log_printf (" iks_id . . . . . . . : 0x%lx", ptr_server->iks_id); + weechat_log_printf (" iks_server_name. . . : '%s'", ptr_server->iks_server_name); + weechat_log_printf (" iks_password . . . . : (hidden)"); + weechat_log_printf (" iks_filter . . . . . : 0x%lx", ptr_server->iks_filter); + weechat_log_printf (" iks_roster . . . . . : 0x%lx", ptr_server->iks_roster); + weechat_log_printf (" iks_features . . . . : %d", ptr_server->iks_features); + weechat_log_printf (" iks_authorized . . . : %d", ptr_server->iks_authorized); + weechat_log_printf (" hook_connect . . . . : 0x%lx", ptr_server->hook_connect); + weechat_log_printf (" hook_fd. . . . . . . : 0x%lx", ptr_server->hook_fd); + weechat_log_printf (" is_connected . . . . : %d", ptr_server->is_connected); + weechat_log_printf (" tls_connected. . . . : %d", ptr_server->tls_connected); +#ifdef HAVE_GNUTLS + weechat_log_printf (" gnutls_sess. . . . . : 0x%lx", ptr_server->gnutls_sess); +#endif + weechat_log_printf (" reconnect_start. . . : %ld", ptr_server->reconnect_start); + weechat_log_printf (" command_time . . . . : %ld", ptr_server->command_time); + weechat_log_printf (" reconnect_join . . . : %d", ptr_server->reconnect_join); + weechat_log_printf (" disable_autojoin . . : %d", ptr_server->disable_autojoin); + weechat_log_printf (" is_away. . . . . . . : %d", ptr_server->is_away); + weechat_log_printf (" away_message . . . . : '%s'", ptr_server->away_message); + weechat_log_printf (" away_time. . . . . . : %ld", ptr_server->away_time); + weechat_log_printf (" lag. . . . . . . . . : %d", ptr_server->lag); + weechat_log_printf (" lag_check_time . . . : tv_sec:%d, tv_usec:%d", + ptr_server->lag_check_time.tv_sec, + ptr_server->lag_check_time.tv_usec); + weechat_log_printf (" lag_next_check . . . : %ld", ptr_server->lag_next_check); + weechat_log_printf (" buffer . . . . . . . : 0x%lx", ptr_server->buffer); + weechat_log_printf (" buffer_as_string . . : '%s'", ptr_server->buffer_as_string); + weechat_log_printf (" buddies_count. . . . : %d", ptr_server->buddies_count); + weechat_log_printf (" buddies. . . . . . . : 0x%lx", ptr_server->buddies); + weechat_log_printf (" last_buddy . . . . . : 0x%lx", ptr_server->last_buddy); + weechat_log_printf (" mucs . . . . . . . . : 0x%lx", ptr_server->mucs); + weechat_log_printf (" last_muc . . . . . . : 0x%lx", ptr_server->last_muc); + weechat_log_printf (" prev_server. . . . . : 0x%lx", ptr_server->prev_server); + weechat_log_printf (" next_server. . . . . : 0x%lx", ptr_server->next_server); + + for (ptr_buddy = ptr_server->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + jabber_buddy_print_log (ptr_buddy); + } + + for (ptr_muc = ptr_server->mucs; ptr_muc; + ptr_muc = ptr_muc->next_muc) + { + jabber_muc_print_log (ptr_muc); + } + } +} diff --git a/src/plugins/jabber/jabber-server.h b/src/plugins/jabber/jabber-server.h new file mode 100644 index 000000000..5a0a01149 --- /dev/null +++ b/src/plugins/jabber/jabber-server.h @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_SERVER_H +#define __WEECHAT_JABBER_SERVER_H 1 + +#include <sys/time.h> +#include <regex.h> + +#ifdef HAVE_GNUTLS +#include <gnutls/gnutls.h> +#endif + +#include <iksemel.h> + +enum t_jabber_server_option +{ + JABBER_SERVER_OPTION_USERNAME = 0, /* username on server */ + JABBER_SERVER_OPTION_SERVER, /* server hostname/IP */ + JABBER_SERVER_OPTION_PROXY, /* proxy used for server (optional) */ + JABBER_SERVER_OPTION_IPV6, /* use IPv6 protocol */ + JABBER_SERVER_OPTION_TLS, /* use TLS cryptographic protocol */ + JABBER_SERVER_OPTION_SASL, /* use SASL for auth */ + JABBER_SERVER_OPTION_RESOURCE, /* resource */ + JABBER_SERVER_OPTION_PASSWORD, /* password */ + JABBER_SERVER_OPTION_LOCAL_ALIAS, /* local alias */ + JABBER_SERVER_OPTION_AUTOCONNECT, /* autoconnect to server at startup */ + JABBER_SERVER_OPTION_AUTORECONNECT, /* autoreconnect when disconnected */ + JABBER_SERVER_OPTION_AUTORECONNECT_DELAY, /* delay before next reconnect */ + JABBER_SERVER_OPTION_LOCAL_HOSTNAME,/* custom local hostname */ + JABBER_SERVER_OPTION_COMMAND, /* command to run once connected */ + JABBER_SERVER_OPTION_COMMAND_DELAY, /* delay after execution of command */ + JABBER_SERVER_OPTION_AUTOJOIN, /* MUCs to automatically join */ + JABBER_SERVER_OPTION_AUTOREJOIN, /* auto rejoin MUCs when kicked */ + /* number of server options */ + JABBER_SERVER_NUM_OPTIONS, +}; + +#define JABBER_SERVER_OPTION_BOOLEAN(__server, __index) \ + ((!weechat_config_option_is_null(__server->options[__index])) ? \ + weechat_config_boolean(__server->options[__index]) : \ + ((!weechat_config_option_is_null(jabber_config_server_default[__index])) ? \ + weechat_config_boolean(jabber_config_server_default[__index]) \ + : weechat_config_boolean_default(jabber_config_server_default[__index]))) + +#define JABBER_SERVER_OPTION_INTEGER(__server, __index) \ + ((!weechat_config_option_is_null(__server->options[__index])) ? \ + weechat_config_integer(__server->options[__index]) : \ + ((!weechat_config_option_is_null(jabber_config_server_default[__index])) ? \ + weechat_config_integer(jabber_config_server_default[__index]) \ + : weechat_config_integer_default(jabber_config_server_default[__index]))) + +#define JABBER_SERVER_OPTION_STRING(__server, __index) \ + ((!weechat_config_option_is_null(__server->options[__index])) ? \ + weechat_config_string(__server->options[__index]) : \ + ((!weechat_config_option_is_null(jabber_config_server_default[__index])) ? \ + weechat_config_string(jabber_config_server_default[__index]) \ + : weechat_config_string_default(jabber_config_server_default[__index]))) + +#define JABBER_SERVER_DEFAULT_PORT 5222 +#define JABBER_SERVER_DEFAULT_RESOURCE "WeeChat" + +#define jabber_server_sendf_queued(server, fmt, argz...) \ + if (server) \ + { \ + server->queue_msg = 1; \ + jabber_server_sendf (server, fmt, ##argz); \ + server->queue_msg = 0; \ + } + +struct t_jabber_server +{ + /* user choices */ + char *name; /* internal name of server */ + struct t_config_option *options[JABBER_SERVER_NUM_OPTIONS]; + + /* internal vars */ + int temp_server; /* temporary server (not saved) */ + int reloading_from_config; /* 1 if reloading from config file */ + int reloaded_from_config; /* 1 if reloaded from config file */ + char *address; /* address from "server" option */ + int port; /* port from "server" option */ + char *current_ip; /* current IP address */ + int sock; /* socket for server (IPv4 or IPv6) */ + iksparser *iks_parser; /* parser for libiksemel */ + char *iks_id_string; /* string with id (user@server/resource) */ + iksid *iks_id; /* id for libiksemel */ + char *iks_server_name; /* server name for libiksemel */ + char *iks_password; /* password for libiksemel */ + iksfilter *iks_filter; /* filter for libiksemel */ + iks *iks_roster; /* jabber roster (buddy list) */ + int iks_features; /* stream features */ + int iks_authorized; /* authorized by jabber server */ + struct t_hook *hook_connect; /* connection hook */ + struct t_hook *hook_fd; /* hook for server socket */ + int is_connected; /* 1 if WeeChat is connected to server */ + int tls_connected; /* = 1 if connected with TLS */ +#ifdef HAVE_GNUTLS + gnutls_session_t gnutls_sess; /* gnutls session (only if TLS is used) */ +#endif + time_t reconnect_start; /* this time + delay = reconnect time */ + time_t command_time; /* this time + command_delay = time to */ + /* autojoin MUCs */ + int reconnect_join; /* 1 if opened MUCs to rejoin */ + int disable_autojoin; /* 1 if user asked to not autojoin MUCs */ + int is_away; /* 1 is user is marked as away */ + char *away_message; /* away message, NULL if not away */ + time_t away_time; /* time() when user marking as away */ + int lag; /* lag (in milliseconds) */ + struct timeval lag_check_time; /* last time lag was checked (ping sent) */ + time_t lag_next_check; /* time for next check */ + struct t_gui_buffer *buffer; /* GUI buffer allocated for server */ + char *buffer_as_string; /* used to return buffer info */ + int buddies_count; /* # buddies in roster */ + struct t_jabber_buddy *buddies; /* buddies in roster */ + struct t_jabber_buddy *last_buddy; /* last buddy in roster */ + struct t_jabber_muc *mucs; /* MUCs opened on server */ + struct t_jabber_muc *last_muc; /* last opened MUC on server */ + struct t_jabber_server *prev_server; /* link to previous server */ + struct t_jabber_server *next_server; /* link to next server */ +}; + +/* Jabber messages */ + +struct t_jabber_message +{ + struct t_jabber_server *server; /* server pointer for received msg */ + char *data; /* message content */ + struct t_jabber_message *next_message; /* link to next message */ +}; + +extern struct t_jabber_server *jabber_servers; +extern struct t_jabber_server *jabber_current_server; +#ifdef HAVE_GNUTLS +extern const int gnutls_cert_type_prio[]; +extern const int gnutls_prot_prio[]; +#endif +extern struct t_jabber_message *jabber_recv_msgq, *jabber_msgq_last_msg; +extern char *jabber_server_option_string[]; +extern char *jabber_server_option_default[]; + +extern int jabber_server_valid (struct t_jabber_server *server); +extern int jabber_server_search_option (const char *option_name); +extern struct t_jabber_server *jabber_server_search (const char *server_name); +extern int jabber_server_get_muc_count (struct t_jabber_server *server); +extern int jabber_server_get_pv_count (struct t_jabber_server *server); +extern char *jabber_server_get_name_without_port (const char *name); +extern const char *jabber_server_get_local_name (struct t_jabber_server *server); +extern void jabber_server_set_server (struct t_jabber_server *server, + const char *address); +extern void jabber_server_set_nicks (struct t_jabber_server *server, + const char *nicks); +extern void jabber_server_buffer_set_highlight_words (struct t_gui_buffer *buffer); +extern struct t_jabber_server *jabber_server_alloc (const char *name); +extern void jabber_server_set_buffer_title (struct t_jabber_server *server); +extern struct t_gui_buffer *jabber_server_create_buffer (struct t_jabber_server *server, + int all_servers); +extern void jabber_server_set_current_server (struct t_jabber_server *server); +extern int jabber_server_iks_transport_connect_async (iksparser *parser, + void **socketptr, + const char *server, + const char *server_name, + int port, + void *notify_data, + iksAsyncNotify *notify_func); +extern int jabber_server_iks_transport_send (void *socket, const char *data, + size_t len); +extern int jabber_server_iks_transport_recv (void *socket, char *buffer, + size_t buf_len, int timeout); +extern void jabber_server_iks_transport_close (void *socket); +extern int jabber_server_connect (struct t_jabber_server *server); +extern void jabber_server_auto_connect (); +extern void jabber_server_disconnect (struct t_jabber_server *server, + int reconnect); +extern void jabber_server_disconnect_all (); +extern void jabber_server_free_data (struct t_jabber_server *server); +extern void jabber_server_free (struct t_jabber_server *server); +extern void jabber_server_free_all (); +extern struct t_jabber_server *jabber_server_copy (struct t_jabber_server *server, + const char *new_name); +extern int jabber_server_rename (struct t_jabber_server *server, + const char *new_server_name); +extern int jabber_server_recv_cb (void *arg_server); +extern int jabber_server_timer_cb (void *data); +extern int jabber_server_add_to_infolist (struct t_infolist *infolist, + struct t_jabber_server *server); +extern void jabber_server_print_log (); + +#endif /* jabber-server.h */ diff --git a/src/plugins/jabber/jabber-upgrade.c b/src/plugins/jabber/jabber-upgrade.c new file mode 100644 index 000000000..77aa5b73b --- /dev/null +++ b/src/plugins/jabber/jabber-upgrade.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber-upgrade.c: save/restore Jabber plugin data */ + + +#include <stdio.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-upgrade.h" +#include "jabber-buddy.h" +#include "jabber-buffer.h" +#include "jabber-config.h" +#include "jabber-input.h" +#include "jabber-muc.h" +#include "jabber-server.h" + + +struct t_jabber_server *jabber_upgrade_current_server = NULL; +struct t_jabber_muc *jabber_upgrade_current_muc = NULL; + + +/* + * jabber_upgrade_save_all_data: save servers/MUCs/buddies info to upgrade + * file + */ + +int +jabber_upgrade_save_all_data (struct t_upgrade_file *upgrade_file) +{ + struct t_infolist *infolist; + struct t_jabber_server *ptr_server; + struct t_jabber_muc *ptr_muc; + struct t_jabber_buddy *ptr_buddy; + int rc; + + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + /* save server */ + infolist = weechat_infolist_new (); + if (!infolist) + return 0; + if (!jabber_server_add_to_infolist (infolist, ptr_server)) + { + weechat_infolist_free (infolist); + return 0; + } + rc = weechat_upgrade_write_object (upgrade_file, + JABBER_UPGRADE_TYPE_SERVER, + infolist); + weechat_infolist_free (infolist); + if (!rc) + return 0; + + for (ptr_muc = ptr_server->mucs; ptr_muc; + ptr_muc = ptr_muc->next_muc) + { + /* save MUC */ + infolist = weechat_infolist_new (); + if (!infolist) + return 0; + if (!jabber_muc_add_to_infolist (infolist, ptr_muc)) + { + weechat_infolist_free (infolist); + return 0; + } + rc = weechat_upgrade_write_object (upgrade_file, + JABBER_UPGRADE_TYPE_MUC, + infolist); + weechat_infolist_free (infolist); + if (!rc) + return 0; + + for (ptr_buddy = ptr_muc->buddies; ptr_buddy; + ptr_buddy = ptr_buddy->next_buddy) + { + /* save buddy */ + infolist = weechat_infolist_new (); + if (!infolist) + return 0; + if (!jabber_buddy_add_to_infolist (infolist, ptr_buddy)) + { + weechat_infolist_free (infolist); + return 0; + } + rc = weechat_upgrade_write_object (upgrade_file, + JABBER_UPGRADE_TYPE_BUDDY, + infolist); + weechat_infolist_free (infolist); + if (!rc) + return 0; + } + } + } + + return 1; +} + +/* + * jabber_upgrade_save: save upgrade file + * return 1 if ok, 0 if error + */ + +int +jabber_upgrade_save () +{ + int rc; + struct t_upgrade_file *upgrade_file; + + upgrade_file = weechat_upgrade_create (JABBER_UPGRADE_FILENAME, 1); + if (!upgrade_file) + return 0; + + rc = jabber_upgrade_save_all_data (upgrade_file); + + weechat_upgrade_close (upgrade_file); + + return rc; +} + +/* + * jabber_upgrade_set_buffer_callbacks: restore buffers callbacks (input and + * close) for buffers created by Jabber + * plugin + */ + +void +jabber_upgrade_set_buffer_callbacks () +{ + struct t_infolist *infolist; + struct t_gui_buffer *ptr_buffer; + + infolist = weechat_infolist_get ("buffer", NULL, NULL); + if (infolist) + { + while (weechat_infolist_next (infolist)) + { + if (weechat_infolist_pointer (infolist, "plugin") == weechat_jabber_plugin) + { + ptr_buffer = weechat_infolist_pointer (infolist, "pointer"); + weechat_buffer_set_pointer (ptr_buffer, "close_callback", &jabber_buffer_close_cb); + weechat_buffer_set_pointer (ptr_buffer, "input_callback", &jabber_input_data_cb); + } + } + } +} + +/* + * jabber_upgrade_read_cb: read callback for upgrade + */ + +int +jabber_upgrade_read_cb (int object_id, + struct t_infolist *infolist) +{ + int flags, size, i, index; + char *buf, option_name[64]; + const char *buffer_name, *str, *buddy; + struct t_jabber_buddy *ptr_buddy; + struct t_gui_buffer *ptr_buffer; + + weechat_infolist_reset_item_cursor (infolist); + while (weechat_infolist_next (infolist)) + { + switch (object_id) + { + case JABBER_UPGRADE_TYPE_SERVER: + jabber_upgrade_current_server = jabber_server_search (weechat_infolist_string (infolist, "name")); + if (jabber_upgrade_current_server) + { + jabber_upgrade_current_server->temp_server = + weechat_infolist_integer (infolist, "temp_server"); + jabber_upgrade_current_server->buffer = NULL; + buffer_name = weechat_infolist_string (infolist, "buffer_name"); + if (buffer_name && buffer_name[0]) + { + ptr_buffer = weechat_buffer_search (JABBER_PLUGIN_NAME, + buffer_name); + if (ptr_buffer) + { + jabber_upgrade_current_server->buffer = ptr_buffer; + if (weechat_config_boolean (jabber_config_look_one_server_buffer) + && !jabber_buffer_servers) + { + jabber_buffer_servers = ptr_buffer; + } + if (weechat_infolist_integer (infolist, "selected")) + jabber_current_server = jabber_upgrade_current_server; + } + } + jabber_upgrade_current_server->reconnect_start = weechat_infolist_time (infolist, "reconnect_start"); + jabber_upgrade_current_server->command_time = weechat_infolist_time (infolist, "command_time"); + jabber_upgrade_current_server->reconnect_join = weechat_infolist_integer (infolist, "reconnect_join"); + jabber_upgrade_current_server->disable_autojoin = weechat_infolist_integer (infolist, "disable_autojoin"); + jabber_upgrade_current_server->is_away = weechat_infolist_integer (infolist, "is_away"); + str = weechat_infolist_string (infolist, "away_message"); + if (str) + jabber_upgrade_current_server->away_message = strdup (str); + jabber_upgrade_current_server->away_time = weechat_infolist_time (infolist, "away_time"); + jabber_upgrade_current_server->lag = weechat_infolist_integer (infolist, "lag"); + buf = weechat_infolist_buffer (infolist, "lag_check_time", &size); + if (buf) + memcpy (&(jabber_upgrade_current_server->lag_check_time), buf, size); + jabber_upgrade_current_server->lag_next_check = weechat_infolist_time (infolist, "lag_next_check"); + } + break; + case JABBER_UPGRADE_TYPE_MUC: + if (jabber_upgrade_current_server) + { + jabber_upgrade_current_muc = jabber_muc_new (jabber_upgrade_current_server, + weechat_infolist_integer (infolist, "type"), + weechat_infolist_string (infolist, "name"), + 0); + if (jabber_upgrade_current_muc) + { + str = weechat_infolist_string (infolist, "topic"); + if (str) + jabber_muc_set_topic (jabber_upgrade_current_muc, str); + str = weechat_infolist_string (infolist, "modes"); + if (str) + jabber_upgrade_current_muc->modes = strdup (str); + jabber_upgrade_current_muc->limit = weechat_infolist_integer (infolist, "limit"); + str = weechat_infolist_string (infolist, "key"); + if (str) + jabber_upgrade_current_muc->key = strdup (str); + str = weechat_infolist_string (infolist, "away_message"); + if (str) + jabber_upgrade_current_muc->away_message = strdup (str); + jabber_upgrade_current_muc->nick_completion_reset = weechat_infolist_integer (infolist, "nick_completion_reset"); + for (i = 0; i < 2; i++) + { + index = 0; + while (1) + { + snprintf (option_name, sizeof (option_name), + "buddy_speaking%d_%05d", i, index); + buddy = weechat_infolist_string (infolist, option_name); + if (!buddy) + break; + jabber_muc_buddy_speaking_add (jabber_upgrade_current_muc, + buddy, + i); + index++; + } + } + index = 0; + while (1) + { + snprintf (option_name, sizeof (option_name), + "buddy_speaking_time_buddy_%05d", index); + buddy = weechat_infolist_string (infolist, option_name); + if (!buddy) + break; + snprintf (option_name, sizeof (option_name), + "buddy_speaking_time_time_%05d", index); + jabber_muc_buddy_speaking_time_add (jabber_upgrade_current_muc, + buddy, + weechat_infolist_time (infolist, + option_name)); + index++; + } + } + } + break; + case JABBER_UPGRADE_TYPE_BUDDY: + if (jabber_upgrade_current_server) + { + flags = weechat_infolist_integer (infolist, "flags"); + ptr_buddy = jabber_buddy_new (jabber_upgrade_current_server, + jabber_upgrade_current_muc, + weechat_infolist_string (infolist, "name"), + flags & JABBER_BUDDY_CHANOWNER, + flags & JABBER_BUDDY_CHANADMIN, + flags & JABBER_BUDDY_CHANADMIN2, + flags & JABBER_BUDDY_OP, + flags & JABBER_BUDDY_HALFOP, + flags & JABBER_BUDDY_VOICE, + flags & JABBER_BUDDY_CHANUSER, + flags & JABBER_BUDDY_AWAY); + if (ptr_buddy) + { + str = weechat_infolist_string (infolist, "host"); + if (str) + ptr_buddy->host = strdup (str); + } + } + break; + } + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_upgrade_load: load upgrade file + * return 1 if ok, 0 if error + */ + +int +jabber_upgrade_load () +{ + int rc; + struct t_upgrade_file *upgrade_file; + + jabber_upgrade_set_buffer_callbacks (); + + upgrade_file = weechat_upgrade_create (JABBER_UPGRADE_FILENAME, 0); + rc = weechat_upgrade_read (upgrade_file, &jabber_upgrade_read_cb); + + return rc; +} diff --git a/src/plugins/jabber/jabber-upgrade.h b/src/plugins/jabber/jabber-upgrade.h new file mode 100644 index 000000000..efd83d295 --- /dev/null +++ b/src/plugins/jabber/jabber-upgrade.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_UPGRADE_H +#define __WEECHAT_JABBER_UPGRADE_H 1 + +#define JABBER_UPGRADE_FILENAME "jabber" + +/* For developers: please add new values ONLY AT THE END of enums */ + +enum t_jabber_upgrade_type +{ + JABBER_UPGRADE_TYPE_SERVER = 0, + JABBER_UPGRADE_TYPE_MUC, + JABBER_UPGRADE_TYPE_BUDDY, +}; + +extern int jabber_upgrade_save (); +extern int jabber_upgrade_load (); + +#endif /* jabber-upgrade.h */ diff --git a/src/plugins/jabber/jabber-xmpp.c b/src/plugins/jabber/jabber-xmpp.c new file mode 100644 index 000000000..ffc68452b --- /dev/null +++ b/src/plugins/jabber/jabber-xmpp.c @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber-xmpp.c: XMPP protocol for Jabber plugin */ + + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> + +#include <iksemel.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-xmpp.h" +#include "jabber-buddy.h" +#include "jabber-buffer.h" +#include "jabber-config.h" +#include "jabber-debug.h" +#include "jabber-muc.h" +#include "jabber-server.h" + + +/* + * jabber_xmpp_log_level_for_command: get log level for Jabber command + */ + +int +jabber_xmpp_log_level_for_command (const char *command) +{ + if (!command || !command[0]) + return 0; + + if (strcmp (command, "chat_msg") == 0) + return 1; + + return 3; +} + +/* + * jabber_xmpp_tags: build tags list with Jabber command and/or tags + */ + +const char * +jabber_xmpp_tags (const char *command, const char *tags) +{ + static char string[512]; + int log_level; + char str_log_level[32]; + + log_level = 0; + str_log_level[0] = '\0'; + + if (command && command[0]) + { + log_level = jabber_xmpp_log_level_for_command (command); + if (log_level > 0) + { + snprintf (str_log_level, sizeof (str_log_level), + ",log%d", log_level); + } + } + + if (command && command[0] && tags && tags[0]) + { + snprintf (string, sizeof (string), + "jabber_%s,%s%s", command, tags, str_log_level); + return string; + } + + if (command && command[0]) + { + snprintf (string, sizeof (string), + "jabber_%s%s", command, str_log_level); + return string; + } + + if (tags && tags[0]) + { + snprintf (string, sizeof (string), "%s", tags); + return string; + } + + return NULL; +} + +/* + * jabber_xmpp_recv_chat_message: receive a message + */ + +int +jabber_xmpp_recv_chat_message (struct t_jabber_server *server, + iks *node) +{ + char *attrib_from, *from, *pos; + char *body; + struct t_jabber_muc *ptr_muc; + + attrib_from = iks_find_attrib (node, "from"); + if (!attrib_from || !attrib_from[0]) + return WEECHAT_RC_ERROR; + + body = iks_find_cdata (node, "body"); + if (!body) + return WEECHAT_RC_ERROR; + + pos = strchr (attrib_from, '/'); + from = (pos) ? + weechat_strndup (attrib_from, pos - attrib_from) : strdup (attrib_from); + if (from) + { + ptr_muc = jabber_muc_search (server, from); + if (!ptr_muc) + { + ptr_muc = jabber_muc_new (server, + JABBER_MUC_TYPE_PRIVATE, + from, 0); + if (!ptr_muc) + { + weechat_printf (server->buffer, + _("%s%s: cannot create new " + "private buffer \"%s\""), + jabber_buffer_get_server_prefix (server, + "error"), + JABBER_PLUGIN_NAME, from); + return WEECHAT_RC_ERROR; + } + } + //jabber_muc_set_topic (ptr_channel, address); + + weechat_printf_tags (ptr_muc->buffer, + jabber_xmpp_tags ("chat_msg", "notify_private"), + "%s%s", + jabber_buddy_as_prefix (NULL, + from, + JABBER_COLOR_CHAT_NICK_OTHER), + body); + + weechat_hook_signal_send ("jabber_pv", + WEECHAT_HOOK_SIGNAL_STRING, + body); + free (from); + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_xmpp_send_chat_message: send a message to MUC or buddy + */ + +void +jabber_xmpp_send_chat_message (struct t_jabber_server *server, + struct t_jabber_muc *muc, + const char *message) +{ + iks *msg; + + if (muc->type == JABBER_MUC_TYPE_PRIVATE) + { + msg = iks_make_msg (IKS_TYPE_CHAT, muc->name, message); + if (msg) + { + iks_send (server->iks_parser, msg); + iks_delete (msg); + } + } + else + { + // TODO: send message to MUC + } +} + +/* + * jabber_xmpp_iks_stream_hook: iksemel stream hook + */ + +int +jabber_xmpp_iks_stream_hook (void *user_data, int type, iks *node) +{ + struct t_jabber_server *server; + iks *x, *t; + ikspak *pak; + + server = (struct t_jabber_server *)user_data; + + switch (type) + { + case IKS_NODE_START: + if (JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_TLS) + && !iks_is_secure (server->iks_parser)) + { + iks_start_tls (server->iks_parser); + } + else + { + if (!JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_SASL)) + { + x = iks_make_auth (server->iks_id, + JABBER_SERVER_OPTION_STRING(server, JABBER_SERVER_OPTION_PASSWORD), + iks_find_attrib (node, "id")); + iks_insert_attrib (x, "id", "auth"); + iks_send (server->iks_parser, x); + iks_delete (x); + } + } + break; + case IKS_NODE_NORMAL: + if (strcmp ("stream:features", iks_name (node)) == 0) + { + server->iks_features = iks_stream_features (node); + if (JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_SASL)) + { + if (!JABBER_SERVER_OPTION_BOOLEAN(server, JABBER_SERVER_OPTION_TLS) + || iks_is_secure (server->iks_parser)) + { + if (server->iks_authorized) + { + if (server->iks_features & IKS_STREAM_BIND) + { + t = iks_make_resource_bind (server->iks_id); + iks_send (server->iks_parser, t); + iks_delete (t); + } + if (server->iks_features & IKS_STREAM_SESSION) + { + t = iks_make_session (); + iks_insert_attrib (t, "id", "auth"); + iks_send (server->iks_parser, t); + iks_delete (t); + } + } + else + { + if (server->iks_features & IKS_STREAM_SASL_MD5) + { + iks_start_sasl (server->iks_parser, + IKS_SASL_DIGEST_MD5, + server->iks_id->user, + server->iks_password); + } + else if (server->iks_features & IKS_STREAM_SASL_PLAIN) + { + iks_start_sasl (server->iks_parser, + IKS_SASL_PLAIN, + server->iks_id->user, + server->iks_password); + } + } + } + } + } + else if (strcmp ("failure", iks_name (node)) == 0) + { + weechat_printf (server->buffer, + _("%s%s: SASL authentication failed (check " + "SASL option and password)"), + jabber_buffer_get_server_prefix (server, + "error"), + JABBER_PLUGIN_NAME); + + jabber_server_disconnect (server, 0); + } + else if (strcmp ("success", iks_name (node)) == 0) + { + server->iks_authorized = 1; + iks_send_header (server->iks_parser, server->iks_id->server); + } + else if (strcmp ("message", iks_name (node)) == 0) + { + jabber_xmpp_recv_chat_message (server, node); + } + else + { + pak = iks_packet (node); + iks_filter_packet (server->iks_filter, pak); + } + break; + case IKS_NODE_STOP: + weechat_printf (server->buffer, + _("%s%s: server disconnected"), + jabber_buffer_get_server_prefix (server, "network"), + JABBER_PLUGIN_NAME); + jabber_server_disconnect (server, 1); + break; + case IKS_NODE_ERROR: + weechat_printf (server->buffer, + _("%s%s: stream error"), + jabber_buffer_get_server_prefix (server, + "error"), + JABBER_PLUGIN_NAME); + break; + } + + if (node) + iks_delete (node); + + return IKS_OK; +} + +/* + * jabber_xmpp_iks_log: log + */ + +void +jabber_xmpp_iks_log (void *user_data, const char *data, size_t size, + int is_incoming) +{ + /* make C compiler happy */ + (void) size; + + jabber_debug_printf ((struct t_jabber_server *)user_data, + !is_incoming, 0, + data); +} + +/* + * jabber_xmpp_iks_result: iks result + */ + +int +jabber_xmpp_iks_result (void *user_data, ikspak *pak) +{ + iks *x; + struct t_jabber_server *server; + + /* make C compiler happy */ + (void) pak; + + server = (struct t_jabber_server *)user_data; + + weechat_printf (server->buffer, + _("%s%s: login ok"), + jabber_buffer_get_server_prefix (server, NULL), + JABBER_PLUGIN_NAME); + + x = iks_make_iq (IKS_TYPE_GET, IKS_NS_ROSTER); + iks_insert_attrib (x, "id", "roster"); + iks_send (server->iks_parser, x); + iks_delete (x); + + return IKS_FILTER_EAT; +} + +/* + * jabber_xmpp_iks_error: iks error + */ + +int +jabber_xmpp_iks_error (void *user_data, ikspak *pak) +{ + struct t_jabber_server *server; + + /* make C compiler happy */ + (void) pak; + + server = (struct t_jabber_server *)user_data; + + weechat_printf (server->buffer, + _("%s%s: authentication failed (check SASL option and " + "password)"), + jabber_buffer_get_server_prefix (server, "error"), + JABBER_PLUGIN_NAME); + + jabber_server_disconnect (server, 0); + + return IKS_FILTER_EAT; +} + +/* + * jabber_xmpp_iks_roster: iks roster + */ + +int +jabber_xmpp_iks_roster (void *user_data, ikspak *pak) +{ + struct t_jabber_server *server; + char *jid, *id, *pos; + iks *x; + + server = (struct t_jabber_server *)user_data; + + server->iks_roster = pak->x; + + x = iks_child(pak->query); + while (x) + { + if (iks_strcmp (iks_name(x), "item") == 0) + { + jid = iks_find_attrib (x, "jid"); + if (jid) + { + pos = strchr (jid, '@'); + //id = (pos) ? weechat_strndup (jid, pos - jid) : strdup (jid); + id = strdup (jid); + if (id) + { + jabber_buddy_new (server, NULL, id, 0, 0, 0, 0, 0, 0, 0, 0); + free (id); + } + } + } + x = iks_next (x); + } + if (x) + iks_delete (x); + + return IKS_FILTER_EAT; +} diff --git a/src/plugins/jabber/jabber-xmpp.h b/src/plugins/jabber/jabber-xmpp.h new file mode 100644 index 000000000..c935df3b0 --- /dev/null +++ b/src/plugins/jabber/jabber-xmpp.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_XMPP_H +#define __WEECHAT_JABBER_XMPP_H 1 + +#include <iksemel.h> + +struct t_jabber_server; +struct t_jabber_muc; + +extern const char *jabber_xmpp_tags (const char *command, const char *tags); +extern void jabber_xmpp_send_chat_message (struct t_jabber_server *server, + struct t_jabber_muc *muc, + const char *message); +extern int jabber_xmpp_iks_stream_hook (void *user_data, int type, iks *node); +extern void jabber_xmpp_iks_log (void *user_data, const char *data, + size_t size, int is_incoming); +extern int jabber_xmpp_iks_result (void *user_data, ikspak *pak); +extern int jabber_xmpp_iks_error (void *user_data, ikspak *pak); +extern int jabber_xmpp_iks_roster (void *user_data, ikspak *pak); + +#endif /* jabber-xmpp.h */ diff --git a/src/plugins/jabber/jabber.c b/src/plugins/jabber/jabber.c new file mode 100644 index 000000000..9f8f6a348 --- /dev/null +++ b/src/plugins/jabber/jabber.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* jabber.c: Jabber plugin for WeeChat */ + + +#include <stdlib.h> +#include <string.h> + +#include "../weechat-plugin.h" +#include "jabber.h" +#include "jabber-bar-item.h" +#include "jabber-command.h" +#include "jabber-completion.h" +#include "jabber-config.h" +#include "jabber-debug.h" +#include "jabber-info.h" +#include "jabber-server.h" +#include "jabber-upgrade.h" + + +WEECHAT_PLUGIN_NAME(JABBER_PLUGIN_NAME); +WEECHAT_PLUGIN_DESCRIPTION("Jabber plugin for WeeChat"); +WEECHAT_PLUGIN_AUTHOR("FlashCode <flashcode@flashtux.org>"); +WEECHAT_PLUGIN_VERSION(WEECHAT_VERSION); +WEECHAT_PLUGIN_WEECHAT_VERSION(WEECHAT_VERSION); +WEECHAT_PLUGIN_LICENSE("GPL3"); + +struct t_weechat_plugin *weechat_jabber_plugin = NULL; + +struct t_hook *jabber_hook_timer = NULL; + +int jabber_signal_upgrade_received = 0; /* signal "upgrade" received ? */ + + +/* + * jabber_signal_quit_cb: callback for "quit" signal + */ + +int +jabber_signal_quit_cb (void *data, const char *signal, const char *type_data, + void *signal_data) +{ + struct t_jabber_server *ptr_server; + + /* make C compiler happy */ + (void) data; + (void) signal; + + if (strcmp (type_data, WEECHAT_HOOK_SIGNAL_STRING) == 0) + { + for (ptr_server = jabber_servers; ptr_server; + ptr_server = ptr_server->next_server) + { + jabber_command_quit_server (ptr_server, + (signal_data) ? (char *)signal_data : NULL); + } + } + + return WEECHAT_RC_OK; +} + +/* + * jabber_signal_upgrade_cb: callback for "upgrade" signal + */ + +int +jabber_signal_upgrade_cb (void *data, const char *signal, const char *type_data, + void *signal_data) +{ + /* make C compiler happy */ + (void) data; + (void) signal; + (void) type_data; + (void) signal_data; + + jabber_signal_upgrade_received = 1; + + return WEECHAT_RC_OK; +} + +/* + * weechat_plugin_init: initialize Jabber plugin + */ + +int +weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) +{ + int i, auto_connect, upgrading; + + weechat_plugin = plugin; + + if (!jabber_config_init ()) + return WEECHAT_RC_ERROR; + + if (jabber_config_read () < 0) + return WEECHAT_RC_ERROR; + + jabber_command_init (); + + jabber_info_init (); + + /* hook some signals */ + jabber_debug_init (); + weechat_hook_signal ("quit", &jabber_signal_quit_cb, NULL); + weechat_hook_signal ("upgrade", &jabber_signal_upgrade_cb, NULL); + //weechat_hook_signal ("xfer_send_ready", &jabber_server_xfer_send_ready_cb, NULL); + //weechat_hook_signal ("xfer_resume_ready", &jabber_server_xfer_resume_ready_cb, NULL); + //weechat_hook_signal ("xfer_send_accept_resume", &jabber_server_xfer_send_accept_resume_cb, NULL); + + /* hook completions */ + jabber_completion_init (); + + jabber_bar_item_init (); + + /* look at arguments */ + auto_connect = 1; + upgrading = 0; + for (i = 0; i < argc; i++) + { + if ((weechat_strcasecmp (argv[i], "-a") == 0) + || (weechat_strcasecmp (argv[i], "--no-connect") == 0)) + { + auto_connect = 0; + } + else if ((weechat_strncasecmp (argv[i], JABBER_PLUGIN_NAME, 3) == 0)) + { + /* + if (!jabber_server_alloc_with_url (argv[i])) + { + weechat_printf (NULL, + _("%s%s: error with server from URL " + "(\"%s\"), ignored"), + weechat_prefix ("error"), JABBER_PLUGIN_NAME, + argv[i]); + } + */ + } + else if (weechat_strcasecmp (argv[i], "--upgrade") == 0) + { + upgrading = 1; + } + } + + if (upgrading) + { + if (!jabber_upgrade_load ()) + { + weechat_printf (NULL, + _("%s%s: WARNING: some network connections may " + "still be opened and not visible, you should " + "restart WeeChat now (with /quit)."), + weechat_prefix ("error"), JABBER_PLUGIN_NAME); + } + } + else + { + if (auto_connect) + jabber_server_auto_connect (); + } + + jabber_hook_timer = weechat_hook_timer (1 * 1000, 0, 0, + &jabber_server_timer_cb, NULL); + + return WEECHAT_RC_OK; +} + +/* + * weechat_plugin_end: end Jabber plugin + */ + +int +weechat_plugin_end (struct t_weechat_plugin *plugin) +{ + /* make C compiler happy */ + (void) plugin; + + if (jabber_hook_timer) + weechat_unhook (jabber_hook_timer); + + if (jabber_signal_upgrade_received) + { + jabber_config_write (1); + jabber_upgrade_save (); + } + else + { + jabber_config_write (0); + jabber_server_disconnect_all (); + } + + jabber_server_free_all (); + + jabber_config_free (); + + return WEECHAT_RC_OK; +} diff --git a/src/plugins/jabber/jabber.h b/src/plugins/jabber/jabber.h new file mode 100644 index 000000000..b2d260228 --- /dev/null +++ b/src/plugins/jabber/jabber.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2009 by FlashCode <flashcode@flashtux.org> + * See README for License detail, AUTHORS for developers list. + * + * 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; either version 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef __WEECHAT_JABBER_H +#define __WEECHAT_JABBER_H 1 + +#define weechat_plugin weechat_jabber_plugin +#define JABBER_PLUGIN_NAME "jabber" + +#define JABBER_GET_SERVER(__buffer) \ + struct t_weechat_plugin *buffer_plugin = NULL; \ + struct t_jabber_server *ptr_server = NULL; \ + buffer_plugin = weechat_buffer_get_pointer (__buffer, "plugin"); \ + if (buffer_plugin == weechat_jabber_plugin) \ + jabber_buffer_get_server_muc (__buffer, &ptr_server, NULL); + +#define JABBER_GET_SERVER_MUC(__buffer) \ + struct t_weechat_plugin *buffer_plugin = NULL; \ + struct t_jabber_server *ptr_server = NULL; \ + struct t_jabber_muc *ptr_muc = NULL; \ + buffer_plugin = weechat_buffer_get_pointer (__buffer, "plugin"); \ + if (buffer_plugin == weechat_jabber_plugin) \ + { \ + jabber_buffer_get_server_muc (__buffer, &ptr_server, &ptr_muc); \ + } + +#define JABBER_COLOR_CHAT weechat_color("chat") +#define JABBER_COLOR_CHAT_CHANNEL weechat_color("chat_channel") +#define JABBER_COLOR_CHAT_DELIMITERS weechat_color("chat_delimiters") +#define JABBER_COLOR_CHAT_HOST weechat_color("chat_host") +#define JABBER_COLOR_CHAT_NICK weechat_color("chat_nick") +#define JABBER_COLOR_CHAT_NICK_SELF weechat_color("chat_nick_self") +#define JABBER_COLOR_CHAT_NICK_OTHER weechat_color("chat_nick_other") +#define JABBER_COLOR_CHAT_SERVER weechat_color("chat_server") +#define JABBER_COLOR_NICKLIST_PREFIX1 weechat_color("nicklist_prefix1") +#define JABBER_COLOR_NICKLIST_PREFIX2 weechat_color("nicklist_prefix2") +#define JABBER_COLOR_NICKLIST_PREFIX3 weechat_color("nicklist_prefix3") +#define JABBER_COLOR_NICKLIST_PREFIX4 weechat_color("nicklist_prefix4") +#define JABBER_COLOR_NICKLIST_PREFIX5 weechat_color("nicklist_prefix5") +#define JABBER_COLOR_BAR_FG weechat_color("bar_fg") +#define JABBER_COLOR_BAR_BG weechat_color("bar_bg") +#define JABBER_COLOR_BAR_DELIM weechat_color("bar_delim") +#define JABBER_COLOR_STATUS_NUMBER weechat_color(weechat_config_string(weechat_config_get("weechat.color.status_number"))) +#define JABBER_COLOR_STATUS_NAME weechat_color(weechat_config_string(weechat_config_get("weechat.color.status_name"))) +#define JABBER_COLOR_MESSAGE_JOIN weechat_color(weechat_config_string(jabber_config_color_message_join)) +#define JABBER_COLOR_MESSAGE_QUIT weechat_color(weechat_config_string(jabber_config_color_message_quit)) +#define JABBER_COLOR_INPUT_NICK weechat_color(weechat_config_string(jabber_config_color_input_nick)) +#define JABBER_COLOR_NICK_IN_SERVER_MESSAGE(nick) \ + ((nick && weechat_config_boolean(jabber_config_look_color_nicks_in_server_messages)) ? \ + nick->color : JABBER_COLOR_CHAT_NICK) + +extern struct t_weechat_plugin *weechat_jabber_plugin; + +#endif /* jabber.h */ diff --git a/src/plugins/logger/logger.c b/src/plugins/logger/logger.c index 93ec28736..93f9ae62e 100644 --- a/src/plugins/logger/logger.c +++ b/src/plugins/logger/logger.c @@ -690,12 +690,12 @@ logger_command_cb (void *data, struct t_gui_buffer *buffer, } /* - * logger_buffer_open_signal_cb: callback for "buffer_open" signal + * logger_buffer_opened_signal_cb: callback for "buffer_opened" signal */ int -logger_buffer_open_signal_cb (void *data, const char *signal, - const char *type_data, void *signal_data) +logger_buffer_opened_signal_cb (void *data, const char *signal, + const char *type_data, void *signal_data) { /* make C compiler happy */ (void) data; @@ -971,7 +971,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) weechat_hook_command ("logger", N_("logger plugin configuration"), N_("[list | set level | disable]"), - N_(" list: show logging status for open buffers\n" + N_(" list: show logging status for opened buffers\n" " set: set logging level on current buffer\n" " level: level for messages to be logged (0 = " "logging disabled, 1 = a few messages (most " @@ -1003,7 +1003,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) logger_start_buffer_all (); - weechat_hook_signal ("buffer_open", &logger_buffer_open_signal_cb, NULL); + weechat_hook_signal ("buffer_opened", &logger_buffer_opened_signal_cb, NULL); weechat_hook_signal ("buffer_closing", &logger_buffer_closing_signal_cb, NULL); weechat_hook_signal ("buffer_renamed", &logger_buffer_renamed_signal_cb, NULL); weechat_hook_signal ("logger_backlog", &logger_backlog_signal_cb, NULL); diff --git a/src/plugins/notify/notify.c b/src/plugins/notify/notify.c index 544c35180..1e6ebf535 100644 --- a/src/plugins/notify/notify.c +++ b/src/plugins/notify/notify.c @@ -171,7 +171,7 @@ notify_set_buffer (struct t_gui_buffer *buffer) } /* - * notify_set_buffer_all: set notify for all open buffers + * notify_set_buffer_all: set notify for all opened buffers */ void @@ -337,12 +337,12 @@ notify_config_write () } /* - * notify_buffer_open_signal_cb: callback for "buffer_open" signal + * notify_buffer_opened_signal_cb: callback for "buffer_opened" signal */ int -notify_buffer_open_signal_cb (void *data, const char *signal, - const char *type_data, void *signal_data) +notify_buffer_opened_signal_cb (void *data, const char *signal, + const char *type_data, void *signal_data) { /* make C compiler happy */ (void) data; @@ -475,13 +475,13 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) "reset|none|highlight|message|all", ¬ify_command_cb, NULL); - /* callback when a buffer is open */ - weechat_hook_signal ("buffer_open", ¬ify_buffer_open_signal_cb, NULL); + /* callback when a buffer is opened */ + weechat_hook_signal ("buffer_opened", ¬ify_buffer_opened_signal_cb, NULL); /* callback when a config option is changed */ weechat_hook_config ("notify.buffer.*", ¬ify_config_cb, NULL); - /* set notify for open buffers */ + /* set notify for opened buffers */ notify_set_buffer_all (); return WEECHAT_RC_OK; |