aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--account.c8
-rw-r--r--bitlbee.h1
-rw-r--r--chat.c188
-rw-r--r--chat.h46
-rw-r--r--doc/user-guide/commands.xml132
-rw-r--r--doc/user-guide/misc.xml6
-rw-r--r--irc.c6
-rw-r--r--irc.h8
-rw-r--r--irc_commands.c33
-rw-r--r--protocols/nogaim.c11
-rw-r--r--root_commands.c397
-rw-r--r--storage_xml.c60
13 files changed, 686 insertions, 212 deletions
diff --git a/Makefile b/Makefile
index bae2e770..20feb067 100644
--- a/Makefile
+++ b/Makefile
@@ -9,7 +9,7 @@
-include Makefile.settings
# Program variables
-objects = account.o bitlbee.o crypting.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o
+objects = account.o bitlbee.o chat.o crypting.o help.o ipc.o irc.o irc_commands.o nick.o query.o root_commands.o set.o storage.o $(STORAGE_OBJS) user.o
headers = account.h bitlbee.h commands.h conf.h config.h crypting.h help.h ipc.h irc.h log.h nick.h query.h set.h sock.h storage.h user.h lib/events.h lib/http_client.h lib/ini.h lib/md5.h lib/misc.h lib/proxy.h lib/sha1.h lib/ssl_client.h lib/url.h protocols/nogaim.h
subdirs = lib protocols
diff --git a/account.c b/account.c
index f3e15d7e..cb54731f 100644
--- a/account.c
+++ b/account.c
@@ -189,6 +189,7 @@ account_t *account_get( irc_t *irc, char *id )
void account_del( irc_t *irc, account_t *acc )
{
account_t *a, *l = NULL;
+ struct chat *c, *nc;
if( acc->ic )
/* Caller should have checked, accounts still in use can't be deleted. */
@@ -202,6 +203,13 @@ void account_del( irc_t *irc, account_t *acc )
else
irc->accounts = a->next;
+ for( c = irc->chatrooms; c; c = nc )
+ {
+ nc = c->next;
+ if( acc == c->acc )
+ chat_del( irc, c );
+ }
+
while( a->set )
set_del( &a->set, a->set->key );
diff --git a/bitlbee.h b/bitlbee.h
index 9c988caa..2224b691 100644
--- a/bitlbee.h
+++ b/bitlbee.h
@@ -128,6 +128,7 @@
#include "commands.h"
#include "account.h"
#include "nick.h"
+#include "chat.h"
#include "conf.h"
#include "log.h"
#include "ini.h"
diff --git a/chat.c b/chat.c
new file mode 100644
index 00000000..d60655de
--- /dev/null
+++ b/chat.c
@@ -0,0 +1,188 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2008 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Keep track of chatrooms the user is interested in */
+
+/*
+ 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 2 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 with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "bitlbee.h"
+
+struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel )
+{
+ struct chat *c, *l;
+ set_t *s;
+
+ if( !chat_chanok( channel ) )
+ return NULL;
+
+ if( chat_chancmp( channel, irc->channel ) == 0 )
+ return NULL;
+
+ for( c = irc->chatrooms; c; c = c->next )
+ {
+ if( chat_chancmp( channel, c->channel ) == 0 )
+ return NULL;
+
+ if( acc == c->acc && g_strcasecmp( handle, c->handle ) == 0 )
+ return NULL;
+
+ l = c;
+ }
+
+ if( irc->chatrooms == NULL )
+ irc->chatrooms = c = g_new0( struct chat, 1 );
+ else
+ l->next = c = g_new0( struct chat, 1 );
+
+ c->acc = acc;
+ c->handle = g_strdup( handle );
+ c->channel = g_strdup( channel );
+
+ s = set_add( &c->set, "auto_join", "false", set_eval_bool, c );
+ /* s = set_add( &c->set, "auto_rejoin", "false", set_eval_bool, c ); */
+ s = set_add( &c->set, "nick", NULL, NULL, c );
+ s->flags |= SET_NULL_OK;
+
+ return c;
+}
+
+struct chat *chat_byhandle( irc_t *irc, account_t *acc, char *handle )
+{
+ struct chat *c;
+
+ for( c = irc->chatrooms; c; c = c->next )
+ {
+ if( acc == c->acc && g_strcasecmp( handle, c->handle ) == 0 )
+ break;
+ }
+
+ return c;
+}
+
+struct chat *chat_bychannel( irc_t *irc, char *channel )
+{
+ struct chat *c;
+
+ for( c = irc->chatrooms; c; c = c->next )
+ {
+ if( chat_chancmp( channel, c->channel ) == 0 )
+ break;
+ }
+
+ return c;
+}
+
+struct chat *chat_get( irc_t *irc, char *id )
+{
+ struct chat *c, *ret = NULL;
+ int nr;
+
+ if( sscanf( id, "%d", &nr ) == 1 && nr < 1000 )
+ {
+ for( c = irc->chatrooms; c; c = c->next )
+ if( ( nr-- ) == 0 )
+ return c;
+
+ return NULL;
+ }
+
+ for( c = irc->chatrooms; c; c = c->next )
+ {
+ if( strstr( c->handle, id ) )
+ {
+ if( !ret )
+ ret = c;
+ else
+ return NULL;
+ }
+ else if( strstr( c->channel, id ) )
+ {
+ if( !ret )
+ ret = c;
+ else
+ return NULL;
+ }
+ }
+
+ return ret;
+}
+
+int chat_del( irc_t *irc, struct chat *chat )
+{
+ struct chat *c, *l = NULL;
+
+ for( c = irc->chatrooms; c; c = (l=c)->next )
+ if( c == chat )
+ break;
+
+ if( c == NULL )
+ return 0;
+ else if( l == NULL )
+ irc->chatrooms = c->next;
+ else
+ l->next = c->next;
+
+ while( c->set )
+ set_del( &c->set, c->set->key );
+
+ g_free( c->handle );
+ g_free( c->channel );
+ g_free( c );
+
+ return 1;
+}
+
+int chat_chancmp( char *a, char *b )
+{
+ if( !chat_chanok( a ) || !chat_chanok( b ) )
+ return 0;
+
+ if( a[0] == b[0] )
+ return nick_cmp( a + 1, b + 1 );
+ else
+ return -1;
+}
+
+int chat_chanok( char *a )
+{
+ if( strchr( CTYPES, a[0] ) != NULL )
+ return nick_ok( a + 1 );
+ else
+ return 0;
+}
+
+int chat_join( irc_t *irc, struct chat *c )
+{
+ struct groupchat *gc;
+ char *nick = set_getstr( &c->set, "nick" );
+
+ if( nick == NULL )
+ nick = irc->nick;
+
+ if( ( gc = c->acc->prpl->chat_join( c->acc->ic, c->handle, nick, NULL ) ) )
+ {
+ g_free( gc->channel );
+ gc->channel = g_strdup( c->channel );
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/chat.h b/chat.h
new file mode 100644
index 00000000..78e54f24
--- /dev/null
+++ b/chat.h
@@ -0,0 +1,46 @@
+ /********************************************************************\
+ * BitlBee -- An IRC to other IM-networks gateway *
+ * *
+ * Copyright 2002-2008 Wilmer van der Gaast and others *
+ \********************************************************************/
+
+/* Keep track of chatrooms the user is interested in */
+
+/*
+ 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 2 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 with
+ the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
+ if not, write to the Free Software Foundation, Inc., 59 Temple Place,
+ Suite 330, Boston, MA 02111-1307 USA
+*/
+
+struct chat
+{
+ account_t *acc;
+
+ char *handle;
+ char *channel;
+ set_t *set;
+
+ struct chat *next;
+};
+
+struct chat *chat_add( irc_t *irc, account_t *acc, char *handle, char *channel );
+struct chat *chat_byhandle( irc_t *irc, account_t *acc, char *handle );
+struct chat *chat_bychannel( irc_t *irc, char *channel );
+struct chat *chat_get( irc_t *irc, char *id );
+int chat_del( irc_t *irc, struct chat *chat );
+
+int chat_chancmp( char *a, char *b );
+int chat_chanok( char *a );
+
+int chat_join( irc_t *irc, struct chat *c );
diff --git a/doc/user-guide/commands.xml b/doc/user-guide/commands.xml
index cd16808e..e50aed19 100644
--- a/doc/user-guide/commands.xml
+++ b/doc/user-guide/commands.xml
@@ -124,7 +124,7 @@
<description>
<para>
- This command gives you a list of all the accounts known by BitlBee, including the numbers you'll need for most account commands.
+ This command gives you a list of all the accounts known by BitlBee.
</para>
</description>
</bitlbee-command>
@@ -137,11 +137,11 @@
<description>
<para>
- This account can be used to change various settings for IM accounts. For all protocols, this command can be used to change the handle or the password BitlBee uses to log in and if it should be logged in automatically. Some protocols have additional settings. You can see the settings available for a connection by typing <emphasis>account set &lt;account id&gt;</emphasis>.
+ This command can be used to change various settings for IM accounts. For all protocols, this command can be used to change the handle or the password BitlBee uses to log in and if it should be logged in automatically. Some protocols have additional settings. You can see the settings available for a connection by typing <emphasis>account set &lt;account id&gt;</emphasis>.
</para>
<para>
- For more infomation about a setting, see <emphasis>help set &lt;setting&gt;</emphasis>. For details about the syntax of this command, see <emphasis>help set</emphasis>.
+ For more infomation about a setting, see <emphasis>help set &lt;setting&gt;</emphasis>.
</para>
<para>
@@ -151,6 +151,89 @@
</bitlbee-command>
</bitlbee-command>
+ <bitlbee-command name="chat">
+ <short-description>Chatroom list maintenance</short-description>
+ <syntax>chat &lt;action&gt; [&lt;arguments&gt;]</syntax>
+
+ <description>
+
+ <para>
+ Available actions: add, del, list, with and set. See <emphasis>help chat &lt;action&gt;</emphasis> for more information.
+ </para>
+
+ </description>
+
+ <bitlbee-command name="add">
+ <syntax>chat add &lt;account&gt; &lt;room&gt; [&lt;channel&gt;]</syntax>
+
+ <description>
+ <para>
+ Add a chatroom to the list of chatrooms you're interested in. BitlBee needs this list to map room names to a proper IRC channel name.
+ </para>
+
+ <para>
+ After adding a room to your list, you can simply use the IRC /join command to enter the room. Also, you can tell BitlBee to automatically join the room when you log in. (See <emphasis>chat set</emphasis>)
+ </para>
+ </description>
+
+ </bitlbee-command>
+
+ <bitlbee-command name="del">
+ <syntax>chat del &lt;chat id&gt;</syntax>
+
+ <description>
+ <para>
+ This commands deletes an chatroom from your list.
+ </para>
+
+ <para>
+ The room ID can be a number (see <emphasis>chat list</emphasis>), or (part of) the name of the room/channel.
+ </para>
+ </description>
+ </bitlbee-command>
+
+ <bitlbee-command name="list">
+ <syntax>chat list</syntax>
+
+ <description>
+ <para>
+ This command gives you a list of all the chatrooms known by BitlBee.
+ </para>
+ </description>
+ </bitlbee-command>
+
+ <bitlbee-command name="with">
+ <syntax>chat with &lt;nickname&gt;</syntax>
+
+ <description>
+ <para>
+ While most <emphasis>chat</emphasis> subcommands are about named chatrooms, this command can be used to open an unnamed groupchat with one or more persons. This command is what <emphasis>/join #nickname</emphasis> used to do in older BitlBee versions.
+ </para>
+ </description>
+ </bitlbee-command>
+
+ <bitlbee-command name="set">
+ <syntax>chat set &lt;chat id&gt;</syntax>
+ <syntax>chat set &lt;chat id&gt;/&lt;setting&gt;</syntax>
+ <syntax>chat set &lt;chat id&gt;/&lt;setting&gt; &lt;value&gt;</syntax>
+ <syntax>chat set -del &lt;chat id&gt;/&lt;setting&gt;</syntax>
+
+ <description>
+ <para>
+ This command can be used to change various settings for chatrooms.
+ </para>
+
+ <para>
+ For more infomation about a setting, see <emphasis>help set &lt;setting&gt;</emphasis>.
+ </para>
+
+ <para>
+ The room ID can be a number (see <emphasis>chat list</emphasis>), or (part of) the name of the room/channel.
+ </para>
+ </description>
+ </bitlbee-command>
+ </bitlbee-command>
+
<bitlbee-command name="add">
<short-description>Add a buddy to your contact list</short-description>
<syntax>add &lt;connection&gt; &lt;handle&gt; [&lt;nick&gt;]</syntax>
@@ -302,6 +385,16 @@
</description>
</bitlbee-setting>
+ <bitlbee-setting name="auto_join" type="boolean" scope="chat">
+ <default>false</default>
+
+ <description>
+ <para>
+ With this option enabled, BitlBee will automatically join this chatroom when you log in.
+ </para>
+ </description>
+ </bitlbee-setting>
+
<bitlbee-setting name="auto_reconnect" type="boolean" scope="both">
<default>false</default>
@@ -485,6 +578,15 @@
</bitlbee-setting>
+ <bitlbee-setting name="nick" type="string" scope="chat">
+
+ <description>
+ <para>
+ You can use this option to set your nickname in a chatroom. You won't see this nickname yourself, but other people in the room will. By default, BitlBee will use your username as the chatroom nickname.
+ </para>
+ </description>
+ </bitlbee-setting>
+
<bitlbee-setting name="ops" type="string" scope="global">
<default>both</default>
<possible-values>both, root, user, none</possible-values>
@@ -853,28 +955,4 @@
</ircexample>
</bitlbee-command>
-
- <bitlbee-command name="join_chat">
- <short-description>Join a named groupchat/conference room</short-description>
- <syntax>join_chat &lt;connection&gt; &lt;room name&gt; [&lt;channel name&gt;] [&lt;room nickname&gt;] [&lt;password&gt;]</syntax>
-
- <description>
- <para>
- On most IM-networks groupchats can be started using the /join command. (<emphasis>/join #foo</emphasis> to start a chatroom with you and <emphasis>foo</emphasis>) This doesn't work with names groupchats though (which exist on Jabber networks and AIM, for example), instead you can use this command.
- </para>
-
- <para>
- The first two arguments are required. <emphasis>room name</emphasis> is the name of the chatroom on the IM-network. <emphasis>channel name</emphasis> is the IRC channel name BitlBee should map this to. <emphasis>room nickname</emphasis> is the nickname you want to have in this channel. If you don't give these options, BitlBee will do the right guesses.
- </para>
-
- <para>
- The following command will join you to the chatroom called <emphasis>bitlbee@conference.bitlbee.org</emphasis>. The channel will be called <emphasis>&amp;bitlbee-help</emphasis> because <emphasis>&amp;bitlbee</emphasis> will already be in use. Your nickname will be <emphasis>help-me</emphasis>.
- </para>
- </description>
-
- <ircexample>
- <ircline nick="wilmer">join_chat jabber bitlbee@conference.bitlbee.org &amp;bitlbee-help help-me</ircline>
- </ircexample>
-
- </bitlbee-command>
</chapter>
diff --git a/doc/user-guide/misc.xml b/doc/user-guide/misc.xml
index b55a8915..3102b8b0 100644
--- a/doc/user-guide/misc.xml
+++ b/doc/user-guide/misc.xml
@@ -68,15 +68,15 @@ Of course you can also create your own groupchats. Type <emphasis>help groupchat
<title>Creating groupchats</title>
<para>
-If you want to start a groupchat with the person <emphasis>lisa_msn</emphasis> in it, just join the channel <emphasis>#lisa_msn</emphasis>. BitlBee will refuse to join you to the channel with that name, but it will create a new virtual channel with root, you and lisa_msn in it.
+To open a groupchat, use the <emphasis>chat with</emphasis> command. For example, to start a groupchat with the person <emphasis>lisa_msn</emphasis> in it, just type <emphasis>chat with lisa_msn</emphasis>. BitlBee will create a new virtual channel with root, you and lisa_msn in it.
</para>
<para>
-Of course a channel with only two people isn't really exciting yet. So the next step is to invite some other people to the channel. For this, you can use the <emphasis>/invite</emphasis> command of your IRC client. Please do keep in mind that all the people have to be on the same network and contact list! You can't invite Yahoo! buddies into an MSN groupchat.
+Then, just use the ordinary IRC <emphasis>/invite</emphasis> command to invite more people. Please do keep in mind that all the people have to be on the same network and contact list! You can't invite Yahoo! buddies into an MSN groupchat.
</para>
<para>
-Some protocols (like Jabber) also support named groupchats. BitlBee now supports these too. You can use the <emphasis>join_chat</emphasis> command to join them. See <emphasis>help join_chat</emphasis> for more information.
+Some protocols (like Jabber) also support named groupchats. BitlBee now supports these too. You can use the <emphasis>chat add</emphasis> command to join them. See <emphasis>help chat_add</emphasis> for more information.
</para>
</sect1>
diff --git a/irc.c b/irc.c
index dd244c09..10b4fd83 100644
--- a/irc.c
+++ b/irc.c
@@ -780,7 +780,9 @@ void irc_login( irc_t *irc )
irc_reply( irc, 2, ":Host %s is running BitlBee " BITLBEE_VERSION " " ARCH "/" CPU ".", irc->myhost );
irc_reply( irc, 3, ":%s", IRCD_INFO );
irc_reply( irc, 4, "%s %s %s %s", irc->myhost, BITLBEE_VERSION, UMODES UMODES_PRIV, CMODES );
- irc_reply( irc, 5, "PREFIX=(ov)@+ CHANTYPES=#& CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server", CMODES, MAX_NICK_LENGTH - 1 );
+ irc_reply( irc, 5, "PREFIX=(ov)@+ CHANTYPES=%s CHANMODES=,,,%s NICKLEN=%d NETWORK=BitlBee "
+ "CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server",
+ CTYPES, CMODES, MAX_NICK_LENGTH - 1 );
irc_motd( irc );
irc->umode[0] = '\0';
irc_umode_set( irc, "+" UMODE, 1 );
@@ -1021,7 +1023,7 @@ int irc_send( irc_t *irc, char *nick, char *s, int flags )
struct groupchat *c = NULL;
user_t *u = NULL;
- if( *nick == '#' || *nick == '&' )
+ if( strchr( CTYPES, *nick ) )
{
if( !( c = irc_chat_by_channel( irc, nick ) ) )
{
diff --git a/irc.h b/irc.h
index b8c52925..f9b2a5b9 100644
--- a/irc.h
+++ b/irc.h
@@ -37,6 +37,7 @@
#define CMODES "nt"
#define CMODE "t"
#define UMODE "s"
+#define CTYPES "&#"
typedef enum
{
@@ -47,11 +48,6 @@ typedef enum
USTATUS_SHUTDOWN = 8
} irc_status_t;
-typedef struct channel
-{
- char *name;
-} channel_t;
-
typedef struct irc
{
int fd;
@@ -86,6 +82,7 @@ typedef struct irc
struct query *queries;
struct account *accounts;
+ struct chat *chatrooms;
struct __USER *users;
GHashTable *userhash;
@@ -99,7 +96,6 @@ typedef struct irc
} irc_t;
#include "user.h"
-// #include "nick.h"
extern GSList *irc_connection_list;
diff --git a/irc_commands.c b/irc_commands.c
index fb2bc7cf..8941b0e9 100644
--- a/irc_commands.c
+++ b/irc_commands.c
@@ -124,7 +124,7 @@ static void irc_cmd_oper( irc_t *irc, char **cmd )
static void irc_cmd_mode( irc_t *irc, char **cmd )
{
- if( *cmd[1] == '#' || *cmd[1] == '&' )
+ if( strchr( CTYPES, *cmd[1] ) )
{
if( cmd[2] )
{
@@ -192,27 +192,18 @@ static void irc_cmd_join( irc_t *irc, char **cmd )
RFC doesn't have any reply for that though? */
else if( cmd[1] )
{
- if( ( cmd[1][0] == '#' || cmd[1][0] == '&' ) && cmd[1][1] )
+ struct chat *c;
+ user_t *u;
+
+ if( strchr( CTYPES, cmd[1][0] ) == NULL || cmd[1][1] == 0 )
{
- user_t *u = user_find( irc, cmd[1] + 1 );
-
- if( u && u->ic && u->ic->acc->prpl->chat_with )
- {
- irc_reply( irc, 403, "%s :Initializing groupchat in a different channel", cmd[1] );
-
- if( !u->ic->acc->prpl->chat_with( u->ic, u->handle ) )
- {
- irc_usermsg( irc, "Could not open a groupchat with %s.", u->nick );
- }
- }
- else if( u )
- {
- irc_reply( irc, 403, "%s :Groupchats are not possible with %s", cmd[1], cmd[1]+1 );
- }
- else
- {
- irc_reply( irc, 403, "%s :No such nick", cmd[1] );
- }
+ irc_reply( irc, 403, "%s :No such channel", cmd[1] );
+ return;
+ }
+
+ if( ( c = chat_bychannel( irc, cmd[1] ) ) )
+ {
+ chat_join( irc, c );
}
else
{
diff --git a/protocols/nogaim.c b/protocols/nogaim.c
index 6a267adf..20d2f3f1 100644
--- a/protocols/nogaim.c
+++ b/protocols/nogaim.c
@@ -248,6 +248,8 @@ static gboolean send_keepalive( gpointer d, gint fd, b_input_condition cond )
void imcb_connected( struct im_connection *ic )
{
+ irc_t *irc = ic->irc;
+ struct chat *c;
user_t *u;
/* MSN servers sometimes redirect you to a different server and do
@@ -270,6 +272,15 @@ void imcb_connected( struct im_connection *ic )
/* Apparently we're connected successfully, so reset the
exponential backoff timer. */
ic->acc->auto_reconnect_delay = 0;
+
+ for( c = irc->chatrooms; c; c = c->next )
+ {
+ if( c->acc != ic->acc )
+ continue;
+
+ if( set_getbool( &c->set, "auto_join" ) )
+ chat_join( irc, c );
+ }
}
gboolean auto_reconnect( gpointer data, gint fd, b_input_condition cond )
diff --git a/root_commands.c b/root_commands.c
index 57d5c91a..8770e707 100644
--- a/root_commands.c
+++ b/root_commands.c
@@ -77,6 +77,18 @@ void root_command_string( irc_t *irc, user_t *u, char *command, int flags )
root_command( irc, cmd );
}
+#define MIN_ARGS( x, y... ) \
+ do \
+ { \
+ int blaat; \
+ for( blaat = 0; blaat <= x; blaat ++ ) \
+ if( cmd[blaat] == NULL ) \
+ { \
+ irc_usermsg( irc, "Not enough parameters given (need %d).", x ); \
+ return y; \
+ } \
+ } while( 0 )
+
void root_command( irc_t *irc, char *cmd[] )
{
int i;
@@ -87,11 +99,8 @@ void root_command( irc_t *irc, char *cmd[] )
for( i = 0; commands[i].command; i++ )
if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
{
- if( !cmd[commands[i].required_parameters] )
- {
- irc_usermsg( irc, "Not enough parameters given (need %d)", commands[i].required_parameters );
- return;
- }
+ MIN_ARGS( commands[i].required_parameters );
+
commands[i].execute( irc, cmd );
return;
}
@@ -249,6 +258,114 @@ static void cmd_showset( irc_t *irc, set_t **head, char *key )
irc_usermsg( irc, "%s is empty", key );
}
+typedef set_t** (*cmd_set_findhead)( irc_t*, char* );
+
+static int cmd_set_real( irc_t *irc, char **cmd, cmd_set_findhead findhead )
+{
+ char *set_full = NULL, *set_name = NULL, *tmp;
+ set_t **head;
+
+ if( cmd[1] && g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
+ {
+ MIN_ARGS( 2, 0 );
+ set_full = cmd[2];
+ }
+ else
+ set_full = cmd[1];
+
+ if( findhead == NULL )
+ {
+ set_name = set_full;
+
+ head = &irc->set;
+ }
+ else
+ {
+ char *id;
+
+ if( ( tmp = strchr( set_full, '/' ) ) )
+ {
+ id = g_strndup( set_full, ( tmp - set_full ) );
+ set_name = tmp + 1;
+ }
+ else
+ {
+ id = g_strdup( set_full );
+ }
+
+ if( ( head = findhead( irc, id ) ) == NULL )
+ {
+ g_free( id );
+ irc_usermsg( irc, "Could not find setting." );
+ return 0;
+ }
+ g_free( id );
+ }
+
+ if( cmd[1] && cmd[2] && set_name )
+ {
+ set_t *s = set_find( head, set_name );
+ int st;
+
+ /*
+ FIXME: Make these work again. Probably a gross hack.
+
+ if( a->ic && s && s->flags & ACC_SET_OFFLINE_ONLY )
+ {
+ irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" );
+ return 0;
+ }
+ else if( !a->ic && s && s->flags & ACC_SET_ONLINE_ONLY )
+ {
+ irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" );
+ return 0;
+ }
+ */
+
+ if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
+ st = set_reset( head, set_name );
+ else
+ st = set_setstr( head, set_name, cmd[2] );
+
+ if( set_getstr( head, set_name ) == NULL )
+ {
+ if( st )
+ irc_usermsg( irc, "Setting changed successfully" );
+ else
+ irc_usermsg( irc, "Failed to change setting" );
+ }
+ else
+ {
+ cmd_showset( irc, head, set_name );
+ }
+ }
+ else if( set_name )
+ {
+ cmd_showset( irc, head, set_name );
+ }
+ else
+ {
+ set_t *s = *head;
+ while( s )
+ {
+ cmd_showset( irc, &s, s->key );
+ s = s->next;
+ }
+ }
+
+ return 1;
+}
+
+static set_t **cmd_account_set_findhead( irc_t *irc, char *id )
+{
+ account_t *a;
+
+ if( ( a = account_get( irc, id ) ) )
+ return &a->set;
+ else
+ return NULL;
+}
+
static void cmd_account( irc_t *irc, char **cmd )
{
account_t *a;
@@ -263,13 +380,9 @@ static void cmd_account( irc_t *irc, char **cmd )
{
struct prpl *prpl;
- if( cmd[2] == NULL || cmd[3] == NULL || cmd[4] == NULL )
- {
- irc_usermsg( irc, "Not enough parameters" );
- return;
- }
+ MIN_ARGS( 4 );
- prpl = find_protocol(cmd[2]);
+ prpl = find_protocol( cmd[2] );
if( prpl == NULL )
{
@@ -289,11 +402,9 @@ static void cmd_account( irc_t *irc, char **cmd )
}
else if( g_strcasecmp( cmd[1], "del" ) == 0 )
{
- if( !cmd[2] )
- {
- irc_usermsg( irc, "Not enough parameters given (need %d)", 2 );
- }
- else if( !( a = account_get( irc, cmd[2] ) ) )
+ MIN_ARGS( 2 );
+
+ if( !( a = account_get( irc, cmd[2] ) ) )
{
irc_usermsg( irc, "Invalid account" );
}
@@ -421,92 +532,13 @@ static void cmd_account( irc_t *irc, char **cmd )
}
else if( g_strcasecmp( cmd[1], "set" ) == 0 )
{
- char *acc_handle, *set_name = NULL, *tmp;
-
- if( !cmd[2] )
- {
- irc_usermsg( irc, "Not enough parameters given (need %d)", 2 );
- return;
- }
-
- if( g_strncasecmp( cmd[2], "-del", 4 ) == 0 )
- acc_handle = g_strdup( cmd[3] );
- else
- acc_handle = g_strdup( cmd[2] );
-
- if( !acc_handle )
- {
- irc_usermsg( irc, "Not enough parameters given (need %d)", 3 );
- return;
- }
-
- if( ( tmp = strchr( acc_handle, '/' ) ) )
- {
- *tmp = 0;
- set_name = tmp + 1;
- }
-
- if( ( a = account_get( irc, acc_handle ) ) == NULL )
- {
- g_free( acc_handle );
- irc_usermsg( irc, "Invalid account" );
- return;
- }
-
- if( cmd[3] && set_name )
- {
- set_t *s = set_find( &a->set, set_name );
- int st;
-
- if( a->ic && s && s->flags & ACC_SET_OFFLINE_ONLY )
- {
- g_free( acc_handle );
- irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "off" );
- return;
- }
- else if( !a->ic && s && s->flags & ACC_SET_ONLINE_ONLY )
- {
- g_free( acc_handle );
- irc_usermsg( irc, "This setting can only be changed when the account is %s-line", "on" );
- return;
- }
-
- if( g_strncasecmp( cmd[2], "-del", 4 ) == 0 )
- st = set_reset( &a->set, set_name );
- else
- st = set_setstr( &a->set, set_name, cmd[3] );
-
- if( set_getstr( &a->set, set_name ) == NULL )
- {
- if( st )
- irc_usermsg( irc, "Setting changed successfully" );
- else
- irc_usermsg( irc, "Failed to change setting" );
- }
- else
- {
- cmd_showset( irc, &a->set, set_name );
- }
- }
- else if( set_name )
- {
- cmd_showset( irc, &a->set, set_name );
- }
- else
- {
- set_t *s = a->set;
- while( s )
- {
- cmd_showset( irc, &s, s->key );
- s = s->next;
- }
- }
+ MIN_ARGS( 2 );
- g_free( acc_handle );
+ cmd_set_real( irc, cmd + 1, cmd_account_set_findhead );
}
else
{
- irc_usermsg( irc, "Unknown command: account %s. Please use \x02help commands\x02 to get a list of available commands.", cmd[1] );
+ irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "account", cmd[1] );
}
}
@@ -836,54 +868,7 @@ static void cmd_yesno( irc_t *irc, char **cmd )
static void cmd_set( irc_t *irc, char **cmd )
{
- char *set_name = cmd[1];
-
- if( cmd[1] && cmd[2] )
- {
- int st;
-
- if( g_strncasecmp( cmd[1], "-del", 4 ) == 0 )
- {
- st = set_reset( &irc->set, cmd[2] );
- set_name = cmd[2];
- }
- else
- {
- st = set_setstr( &irc->set, cmd[1], cmd[2] );
- }
-
- /* Normally we just show the variable's new/unchanged
- value as feedback to the user, but this has always
- caused confusion when changing the password. Give
- other feedback instead: */
- if( set_getstr( &irc->set, set_name ) == NULL )
- {
- if( st )
- irc_usermsg( irc, "Setting changed successfully" );
- else
- irc_usermsg( irc, "Failed to change setting" );
- }
- else
- {
- cmd_showset( irc, &irc->set, set_name );
- }
- }
- else if( set_name )
- {
- cmd_showset( irc, &irc->set, set_name );
-
- if( strchr( set_name, '/' ) )
- irc_usermsg( irc, "Warning: / found in setting name, you're probably looking for the `account set' command." );
- }
- else
- {
- set_t *s = irc->set;
- while( s )
- {
- cmd_showset( irc, &s, s->key );
- s = s->next;
- }
- }
+ cmd_set_real( irc, cmd, NULL );
}
static void cmd_save( irc_t *irc, char **cmd )
@@ -1006,6 +991,122 @@ static void cmd_qlist( irc_t *irc, char **cmd )
static void cmd_join_chat( irc_t *irc, char **cmd )
{
+ irc_usermsg( irc, "This command is now obsolete. "
+ "Please try the `chat' command instead." );
+}
+
+static set_t **cmd_chat_set_findhead( irc_t *irc, char *id )
+{
+ struct chat *c;
+
+ if( ( c = chat_get( irc, id ) ) )
+ return &c->set;
+ else
+ return NULL;
+}
+
+static void cmd_chat( irc_t *irc, char **cmd )
+{
+ account_t *acc;
+ struct chat *c;
+
+ if( g_strcasecmp( cmd[1], "add" ) == 0 )
+ {
+ char *channel, *s;
+
+ MIN_ARGS( 3 );
+
+ if( !( acc = account_get( irc, cmd[2] ) ) )
+ {
+ irc_usermsg( irc, "Invalid account" );
+ return;
+ }
+
+ if( cmd[4] == NULL )
+ {
+ channel = g_strdup( cmd[3] );
+ if( ( s = strchr( channel, '@' ) ) )
+ *s = 0;
+ }
+ else
+ {
+ channel = g_strdup( cmd[4] );
+ }
+
+ if( strchr( CTYPES, channel[0] ) == NULL )
+ {
+ s = g_strdup_printf( "%c%s", CTYPES[0], channel );
+ g_free( channel );
+ channel = s;
+ }
+
+ if( ( c = chat_add( irc, acc, cmd[3], channel ) ) )
+ irc_usermsg( irc, "Chatroom added successfully." );
+ else
+ irc_usermsg( irc, "Could not add chatroom." );
+
+ g_free( channel );
+ }
+ else if( g_strcasecmp( cmd[1], "list" ) == 0 )
+ {
+ int i = 0;
+
+ if( strchr( irc->umode, 'b' ) )
+ irc_usermsg( irc, "Chatroom list:" );
+
+ for( c = irc->chatrooms; c; c = c->next )
+ {
+ irc_usermsg( irc, "%2d. %s(%s) %s, %s", i, c->acc->prpl->name,
+ c->acc->user, c->handle, c->channel );
+
+ i ++;
+ }
+ irc_usermsg( irc, "End of chatroom list" );
+ }
+ else if( g_strcasecmp( cmd[1], "set" ) == 0 )
+ {
+ cmd_set_real( irc, cmd + 1, cmd_chat_set_findhead );
+ }
+ else if( g_strcasecmp( cmd[1], "del" ) == 0 )
+ {
+ MIN_ARGS( 2 );
+
+ if( ( c = chat_get( irc, cmd[2] ) ) )
+ {
+ chat_del( irc, c );
+ }
+ else
+ {
+ irc_usermsg( irc, "Could not remove chat." );
+ }
+ }
+ else if( g_strcasecmp( cmd[1], "with" ) == 0 )
+ {
+ user_t *u;
+
+ MIN_ARGS( 2 );
+
+ if( ( u = user_find( irc, cmd[2] ) ) && u->ic && u->ic->acc->prpl->chat_with )
+ {
+ if( !u->ic->acc->prpl->chat_with( u->ic, u->handle ) )
+ {
+ irc_usermsg( irc, "(Possible) failure while trying to open "
+ "a groupchat with %s.", u->nick );
+ }
+ }
+ else
+ {
+ irc_usermsg( irc, "Can't open a groupchat with %s.", cmd[2] );
+ }
+ }
+ else
+ {
+ irc_usermsg( irc, "Unknown command: %s %s. Please use \x02help commands\x02 to get a list of available commands.", "chat", cmd[1] );
+ }
+
+
+
+#if 0
account_t *a;
struct im_connection *ic;
char *chat, *channel, *nick = NULL, *password = NULL;
@@ -1031,7 +1132,7 @@ static void cmd_join_chat( irc_t *irc, char **cmd )
chat = cmd[2];
if( cmd[3] )
{
- if( cmd[3][0] != '#' && cmd[3][0] != '&' )
+ if( strchr( CTYPES, cmd[3][0] ) == NULL )
channel = g_strdup_printf( "&%s", cmd[3] );
else
channel = g_strdup( cmd[3] );
@@ -1074,6 +1175,7 @@ static void cmd_join_chat( irc_t *irc, char **cmd )
irc_usermsg( irc, "Tried to join chat, not sure if this was successful" );
g_free( channel );
}
+#endif
}
const command_t commands[] = {
@@ -1096,5 +1198,6 @@ const command_t commands[] = {
{ "nick", 1, cmd_nick, 0 },
{ "qlist", 0, cmd_qlist, 0 },
{ "join_chat", 2, cmd_join_chat, 0 },
+ { "chat", 1, cmd_chat, 0 },
{ NULL }
};
diff --git a/storage_xml.c b/storage_xml.c
index d3d0f6d6..b78c3661 100644
--- a/storage_xml.c
+++ b/storage_xml.c
@@ -53,6 +53,8 @@ struct xml_parsedata
irc_t *irc;
char *current_setting;
account_t *current_account;
+ struct chat *current_chat;
+ set_t **current_set_head;
char *given_nick;
char *given_pass;
xml_pass_st pass_st;
@@ -171,7 +173,16 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na
}
if( ( setting = xml_attr( attr_names, attr_values, "name" ) ) )
+ {
+ if( xd->current_chat != NULL )
+ xd->current_set_head = &xd->current_chat->set;
+ else if( xd->current_account != NULL )
+ xd->current_set_head = &xd->current_account->set;
+ else
+ xd->current_set_head = &xd->irc->set;
+
xd->current_setting = g_strdup( setting );
+ }
else
g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"Missing attributes for %s element", element_name );
@@ -193,6 +204,23 @@ static void xml_start_element( GMarkupParseContext *ctx, const gchar *element_na
"Missing attributes for %s element", element_name );
}
}
+ else if( g_strcasecmp( element_name, "chat" ) == 0 )
+ {
+ char *handle, *channel;
+
+ handle = xml_attr( attr_names, attr_values, "handle" );
+ channel = xml_attr( attr_names, attr_values, "channel" );
+
+ if( xd->current_account && handle && channel )
+ {
+ xd->current_chat = chat_add( xd->irc, xd->current_account, handle, channel );
+ }
+ else
+ {
+ g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
+ "Missing attributes for %s element", element_name );
+ }
+ }
else
{
g_set_error( error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
@@ -213,13 +241,16 @@ static void xml_end_element( GMarkupParseContext *ctx, const gchar *element_name
{
xd->current_account = NULL;
}
+ else if( g_strcasecmp( element_name, "chat" ) == 0 )
+ {
+ xd->current_chat = NULL;
+ }
}
static void xml_text( GMarkupParseContext *ctx, const gchar *text_orig, gsize text_len, gpointer data, GError **error )
{
char text[text_len+1];
struct xml_parsedata *xd = data;
- irc_t *irc = xd->irc;
strncpy( text, text_orig, text_len );
text[text_len] = 0;
@@ -232,8 +263,7 @@ static void xml_text( GMarkupParseContext *ctx, const gchar *text_orig, gsize te
}
else if( g_strcasecmp( g_markup_parse_context_get_element( ctx ), "setting" ) == 0 && xd->current_setting )
{
- set_setstr( xd->current_account ? &xd->current_account->set : &irc->set,
- xd->current_setting, (char*) text );
+ set_setstr( xd->current_set_head, xd->current_setting, (char*) text );
g_free( xd->current_setting );
xd->current_setting = NULL;
}
@@ -396,7 +426,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite )
g_free( pass_buf );
for( set = irc->set; set; set = set->next )
- if( set->value && set->def )
+ if( set->value )
if( !xml_printf( fd, 1, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
goto write_error;
@@ -405,6 +435,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite )
unsigned char *pass_cr;
char *pass_b64;
int pass_len;
+ struct chat *c;
pass_len = arc_encode( acc->pass, strlen( acc->pass ), (unsigned char**) &pass_cr, irc->password, 12 );
pass_b64 = base64_encode( pass_cr, pass_len );
@@ -423,7 +454,7 @@ static storage_status_t xml_save( irc_t *irc, int overwrite )
goto write_error;
for( set = acc->set; set; set = set->next )
- if( set->value && set->def && !( set->flags & ACC_SET_NOSAVE ) )
+ if( set->value && !( set->flags & ACC_SET_NOSAVE ) )
if( !xml_printf( fd, 2, "<setting name=\"%s\">%s</setting>\n", set->key, set->value ) )
goto write_error;
@@ -437,6 +468,25 @@ static storage_status_t xml_save( irc_t *irc, int overwrite )
if( g_hash_table_find( acc->nicks, xml_save_nick, & fd ) )
goto write_error;
+ for( c = irc->chatrooms; c; c = c->next )
+ {
+ if( c->acc != acc )
+ continue;
+
+ if( !xml_printf( fd, 2, "<chat handle=\"%s\" channel=\"%s\" type=\"%s\">\n",
+ c->handle, c->channel, "room" ) )
+ goto write_error;
+
+ for( set = c->set; set; set = set->next )
+ if( set->value && !( set->flags & ACC_SET_NOSAVE ) )
+ if( !xml_printf( fd, 3, "<setting name=\"%s\">%s</setting>\n",
+ set->key, set->value ) )
+ goto write_error;
+
+ if( !xml_printf( fd, 2, "</chat>\n" ) )
+ goto write_error;
+ }
+
if( !xml_printf( fd, 1, "</account>\n" ) )
goto write_error;
}