IRC Commands Patch
Manish Malik <[email protected]>
| Newsgroups | gmane.network.instant-messaging.ayttm.user |
|---|---|
| Message-ID | <[email protected]> |
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi, This patch (irc_commands.patch) adds support for common irc-client commands -- /say , /msg , /kick , /quote , etc. * Developed over the latest CVS (modules/irc/irc.c has version 1.39). * To patch, go to the ayttm/ directory of latest CVS source, and: patch -p0 < irc_commands.patch * Note: users tinkering with the source may want to try out adding new command expansions in irc_ca[] (modules/irc/irc.c) * Alternate location: http://mm.bbspals.org/code/ayttm/irc_commands.patch Feedback/comments/suggestions welcome. P.S. If you use it over Freenode, do remember that /msg won't work unless you identify with NickServ. http://freenode.net/faq.shtml#privmsg :) Regards, Manish -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.2 (GNU/Linux) Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org iD8DBQFDgFWX9364pdQFFqARAo40AJ4ss+Os+gTaF0Mp7rz2jBs5ofRTbQCgvn6G 4gJ79DpsHMQ4fvCeXUiOMIY= =+Jel -----END PGP SIGNATURE-----
irc_commands.patch
(text/plain, 8.1 KB)
Index: modules/irc/irc.c
===================================================================
RCS file: /cvsroot/ayttm/ayttm/modules/irc/irc.c,v
retrieving revision 1.39
diff -u -r1.39 irc.c
--- modules/irc/irc.c 13 Feb 2005 13:33:26 -0000 1.39
+++ modules/irc/irc.c 20 Nov 2005 10:09:09 -0000
@@ -173,6 +173,42 @@
static int is_setting_state = 0;
+/* Denotes the end of list in irc_command_action array (irc_ca) ... */
+#define IRC_END_COMMAND ""
+
+/* Max command and action strings length in an irc_command_action struct */
+#define MAX_IRC_COMMAND_LEN 255
+#define MAX_IRC_ACTION_LEN 255
+
+/* IRC_COMMAND_TYPE: type of command in an irc_command_action struct. */
+enum IRC_COMMAND_TYPE
+{
+ IRC_COMMAND_BUILTIN = 1,
+ IRC_COMMAND_USER_DEF = 2
+};
+
+typedef struct irc_command_action_type
+{
+ char command[MAX_IRC_COMMAND_LEN];
+ char action[MAX_IRC_ACTION_LEN];
+ enum IRC_COMMAND_TYPE command_type;
+} irc_command_action;
+
+/* Command-Action array of structs...
+ * Spaces at the end of command-strings are important.
+ * IRC_END_COMMAND is the default action to take, if none of the commands match. */
+static irc_command_action irc_ca[] =
+{
+ { "/ME ", "PRIVMSG %TARGET% :\1ACTION %ARGS%\1\n", IRC_COMMAND_BUILTIN },
+ { "/MSG ", "PRIVMSG %ARGS1% :%ARGS2_ALL%\n", IRC_COMMAND_BUILTIN },
+ { "/QUOTE ", "%ARGS%\n", IRC_COMMAND_BUILTIN },
+ { "/QUIT ", "QUIT :%ARGS%\n", IRC_COMMAND_BUILTIN },
+ { "/SAY ", "PRIVMSG %TARGET% :%ARGS%\n", IRC_COMMAND_BUILTIN },
+ { "/KICK ", "KICK %TARGET% %ARGS1% :%ARGS2_ALL%\n", IRC_COMMAND_BUILTIN },
+ { IRC_END_COMMAND, "PRIVMSG %TARGET% :%ARGS%\n", IRC_COMMAND_BUILTIN }
+};
+
+
/* Local prototypes */
static unsigned char *strip_color (unsigned char *text);
static int sendall(int s, char *buf, int len);
@@ -214,6 +250,9 @@
static void eb_irc_read_prefs_config(LList * values);
static LList * eb_irc_write_prefs_config();
static void irc_connect_cb(int fd, int error, void *data);
+static int irc_replace_string_args(char* source, char **ptarget, const char* match, const char* replacement);
+static int irc_command_to_action(char* message, char* out, int max_out_len, char* target_name);
+
/* taken from X-Chat 1.6.4: src/common/util.c */
/* Added: stripping of CTCP/2 color/formatting attributes, which is
everything between two '\006' = ctrl-F characters.
@@ -1862,10 +1901,14 @@
irc_local_account * ila = (irc_local_account *) room->local_user->protocol_local_account_data;
- if(strncmp(message, "/me ", 4) == 0 && strlen(message) > 4)
- g_snprintf(buff, BUF_LEN, "PRIVMSG %s :\1ACTION %s\1\n", room->room_name, message+4);
- else
+ if (message && (message[0]!='/'))
+ {
g_snprintf(buff, BUF_LEN, "PRIVMSG %s :%s\n", room->room_name, message);
+ }
+ else
+ {
+ irc_command_to_action(message, buff, BUF_LEN, room->room_name);
+ }
ret = sendall(ila->fd, buff, strlen(buff));
if (ret == -1) irc_logout(room->local_user);
@@ -2005,6 +2048,191 @@
return l_list_copy(ila->channel_list);
}
+
+/*
+ * function: irc_replace_string_args
+ * Minion function, utilized by irc_command_to_action()
+ */
+int irc_replace_string_args(char* source, char **ptarget, const char* match,
+ const char* replacement)
+{
+ char *last_matched, *replaced, *last_replaced;
+ int current_replaced_len, difference_len;
+ int match_len = strlen(match);
+ int replacement_len = strlen(replacement);
+ int source_len = strlen(source);
+ int replaced_count = 0;
+
+ if ((NULL == match) || (NULL == replacement) || (match_len < 1)
+ || (source_len < 1) )
+ {
+ return -1; /* Indicates nothing was done */
+ }
+
+ current_replaced_len = source_len;
+ difference_len = replacement_len - match_len;
+
+ last_matched = source; /* initialize lastMatch with source string */
+
+ replaced = g_strdup(source);
+
+ /* Loop through the string to make replacements,
+ * as long as there's a match available */
+ while (last_matched = strstr(last_matched, match))
+ {
+ last_replaced = replaced;
+ current_replaced_len += difference_len;
+ replaced = g_strndup(last_replaced, current_replaced_len);
+ g_free(last_replaced);
+
+ strncpy(replaced, source, last_matched - source);
+ *(replaced + (last_matched - source) ) = '\0'; /* <= replaced length */
+ strcat(replaced, replacement);
+ last_matched += match_len;
+ strcat(replaced, last_matched);
+
+ /* Keep track of how many replacements we're making */
+ ++replaced_count;
+ }
+
+ /* Don't leak memory ... */
+ if ((*ptarget) != NULL)
+ {
+ g_free(*ptarget);
+ *ptarget = NULL;
+ }
+
+ /* Caller's responsibility to g_free() this, and set to NULL */
+ (*ptarget) = replaced;
+
+ /* Let the caller know how many replacements were made */
+ return replaced_count;
+}
+
+
+/*
+ * Function: irc_command_to_action
+ * Recognizes /-commands and replaces text for them in a given message...
+ * Arguments:
+ * message: source message
+ * out: output message buffer.
+ * Should've alrady been allocated memory by the calling function
+ * max_out_len: maximum length of output message buffer (out)
+ * target_name: target (Channel name if coming from irc_send_chat_room_message)
+ */
+
+int irc_command_to_action(char* message, char* out, int max_out_len, char* target_name)
+{
+ irc_command_action *irc_ca_iterator;
+ int command_matched = 0; /* 0 = no command matched, 1 = matched */
+ int command_length = 0; /* 0 if command_matched = 0 */
+ char *work_str; /* Temporary work-string used during calls to replace... */
+ /* replacement string holders */
+ char **args, *message_args, *args_1, *args_2, *args_2_all, *args_3_all;
+
+ /* if either of message or out is NULL, don't bother checking further.
+ * Same goes for max_out_len being 0. */
+ if ((NULL == message) || (NULL == out) || (max_out_len == 0))
+ {
+ if (out != NULL)
+ {
+ out[0] = '\0';
+ }
+ return -1;
+ }
+
+ /* Initialize command_to_action iterator */
+ irc_ca_iterator = &irc_ca[0];
+
+ while (strcmp(irc_ca_iterator->command,IRC_END_COMMAND) != 0)
+ {
+ command_length = strlen(irc_ca_iterator->command);
+
+ if (g_strncasecmp((irc_ca_iterator->command),
+ message, command_length) == 0)
+ {
+ command_matched = 1;
+ strncpy(message, irc_ca_iterator->command, command_length);
+ break; /* break out of the loop. We found it. */
+ }
+
+ irc_ca_iterator++;
+ }
+
+ if (0 == command_matched)
+ {
+ command_length = 0;
+ }
+
+ /* %ARGS% is now (message + command_length) */
+ message_args = message + command_length;
+
+ args_1 = g_malloc0(1); /* first element after command */
+ args_2 = g_malloc0(1); /* second element */
+ args_2_all = g_malloc0(1); /* text after, and including second element */
+ args_3_all = g_malloc0(1); /* text after, and including third element */
+
+ if (strlen(message_args) > 0) /* Use above values for empty %ARGS% */
+ {
+ /* To preserve multiple spaces between args, we'll extract
+ * args_2_all, and args_3_all separately */
+ args = g_strsplit(message_args, " ", 2);
+ if (args && args[0])
+ {
+ g_free(args_1);
+ args_1 = g_strdup(args[0]);
+ if (args[1])
+ {
+ g_free(args_2_all);
+ args_2_all = g_strdup(args[1]);
+ }
+ }
+
+ g_strfreev(args); /* Release whatever g_strsplit allocated for us */
+
+ args = g_strsplit(message_args, " ", 3);
+
+ if (args && args[1])
+ {
+ g_free(args_2);
+ args_2 = g_strdup(args[1]);
+
+ if (args[2])
+ {
+ g_free(args_3_all);
+ args_3_all = g_strdup(args[2]);
+ }
+ }
+
+ g_strfreev(args); /* Again, release whatever g_strsplit allocated */
+ args = NULL;
+ }
+
+ work_str = g_strdup(irc_ca_iterator->action);
+
+ /* Replacement */
+ irc_replace_string_args(work_str, &work_str, "%TARGET%", target_name);
+ irc_replace_string_args(work_str, &work_str, "%ARGS%", message_args);
+ irc_replace_string_args(work_str, &work_str, "%ARGS1%", args_1);
+ irc_replace_string_args(work_str, &work_str, "%ARGS2%", args_2);
+ irc_replace_string_args(work_str, &work_str, "%ARGS2_ALL%", args_2_all);
+ irc_replace_string_args(work_str, &work_str, "%ARGS3_ALL%", args_3_all);
+
+ strncpy(out, work_str, max_out_len);
+ out[max_out_len - 1] = '\0';
+
+ g_free(args_1);
+ g_free(args_2);
+ g_free(args_2_all);
+ g_free(args_3_all);
+
+ g_free(work_str);
+ work_str = NULL;
+
+ return 0;
+}
+
+
struct service_callbacks * query_callbacks()
{
struct service_callbacks * sc;