commit 30cee322c1a4f18825a2ca3de3e0829a73a7b499
parent e180c07caf16b063524b9a8d5c42572e84810537
Author: Antoine Amarilli <ant.amarilli@free.fr>
Date: Fri, 21 Jan 2011 06:04:19 +0100
cleanup, experimental additions
Diffstat:
irctk.c | | | 435 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
1 file changed, 233 insertions(+), 202 deletions(-)
diff --git a/irctk.c b/irctk.c
@@ -35,7 +35,7 @@
#include <unistd.h>
#include <sys/time.h>
-#include "libircclient.h"
+#include <libircclient/libircclient.h>
#include <unistd.h>
#include <pthread.h>
@@ -55,9 +55,14 @@
#define DEFAULT_FIRST 0
#define DEFAULT_LAST_IN 1
#define DEFAULT_LAST_OUT 2
+#define DEFAULT_ALL 3
+
// TODO
#define MAX_LEN 4096
+
+
+
//const char *argp_program_version = "irctk 0.1";
//const char *argp_program_bug_address = "<a3nm@a3nm.net>";
const char *argp_program_version = NULL;
@@ -79,33 +84,33 @@ static char args_doc[] = "[NICK@]SERVER[:PORT] [CHANNEL]...";
#define PARSING 6
/* The options we understand. */
static struct argp_option options[] = {
- /* TODO Display by theme not by alpha order */
+
{"verbose", 'v', 0, 0,
"Produce debug output on stderr", STANDARD, },
{"quiet", 'q', 0, 0,
"Don't even display errors on stderr, fail silently", STANDARD, },
- {"no-command-to-event", 0, 0, 0,
+ /*{"no-command-to-event", 0, 0, 0,
"Don't generate events from messages with \"/quit\", \"/me\"...",
- PARSING, }, /* TODO */
+ PARSING, }, // TODO
{"no-destination-prefix", 0, 0, 0,
"Don't look for []",
- PARSING}, /* TODO */
+ PARSING}, // TODO
{"event-to-command", 'c', 0, 0,
"Translate server events to messages with \"/quit\", \"/me\"...",
- PARSING}, /* TODO */
+ PARSING}, // TODO
{"event-to-message", 'm', 0, 0,
"Translate server events to a human-readable description",
- PARSING}, /* TODO */
+ PARSING}, // TODO */
{"with-host", 'w', 0, 0,
- "Keep the host info in pseudos" , /* TODO use irc_stripnick */
+ "Keep the host info in pseudos" ,
DISPLAY_SELECTION},
- /* TODO, and make compatible with --own */
+ /* TODO make compatible with --own */
{"own", 'o', 0, 0,
"Also display messages posted by self",
DISPLAY_SELECTION},
{"interval", 'i', "secs", 0,
"Wait delay between posted messages (default: 0 for tty stdin, 1 for file/pipe)",
- /* TODO should not delay for bots, only for things piped, is there a
+ /* TODOponey ideally should not delay for bots, only for things piped, is there a
* better way such as only waiting at the end? */
MISC},
{"default-always-first", '0', 0, 0,
@@ -117,25 +122,28 @@ static struct argp_option options[] = {
{"default-last-posted", 'p', 0, 0,
"Post messages to the last posted channel by default",
CHANNEL_SELECTION},
+ {"default-all", 'l', 0, 0,
+ "Post messages to all specified channels by default",
+ CHANNEL_SELECTION},
{"show-inferred", 'P', 0, 0,
"When inferring a next chan with --default-last-posted, display it on stderr",
CHANNEL_SELECTION},
- /* TODO for this option, it would be cool to display the channel name on stderr, for the poor man's client*/
{"synchronous", 's', 0, 0,
"Will wait for a multiline, blankline-terminated answer on stdin to all lines passed on stdout, and will bufferize activity before that", COM_MODE },
- {"exec", 'e', 0, 0,
- "Pipe each message to this command", COM_MODE }, /* TODO and support several of them */
+ /*{"exec", 'e', 0, 0,
+ "Pipe each message to this command", COM_MODE }, // TODO and support several of them
{"exec-argv", 'E', 0, 0,
"Run this command on each message, passing the channel, nick and message as $1, $2, and $3", COM_MODE },
- /* TODO and allow to pipe on argv rather than stdin */
+ */
{"reply", 'r', 0, 0,
"When inferring a destination channel automatically with --last-active, also infer a destination nick, and prefix lines with this nick (blank line terminates)", BOT_OPTIONS },
+ /* TODO externalize those two features as a wrapper script */
{"filter", 'f', 0, 0,
"Only keep messages directly addressed to us (in private channel or with lines prefixed by our nick)", BOT_OPTIONS },
{"filter-prune", 'F', 0, 0,
"Only give the message body without the channel, nick or address (useful with -fr)", BOT_OPTIONS },
- {"no-auto-join", 0, 0, 0,
- "Refuse to send any message to channels not specified on the command line (default is to join as needed)", MISC },
+ /*{"no-auto-join", 0, 0, 0,
+ "Refuse to send any message to channels not specified on the command line (default is to join as needed)", MISC }, // TODO*/
{ 0 }
};
@@ -144,27 +152,27 @@ static struct argp_option options[] = {
*/
struct arguments
{
- char ** channels;
- int n_channels;
- int interval;
- int verbosity;
- int quiet;
- int command;
- char * nick;
- char * server;
- int port;
- int own;
- char * raw_dest;
- char ready;
- char last_chan_in[MAX_LEN];
- char last_nick_in[MAX_LEN];
- char last_chans_out[MAX_LEN];
- int default_destination;
- int show_prefix;
- int show_nick_prefix;
- int with_host;
- int filter;
- int prune;
+ char *nick;
+ char *server;
+ int port;
+ char **channels;
+ int n_channels;
+ int interval;
+ int verbosity;
+ int command;
+ int own;
+ char * raw_dest;
+ char ready;
+ char last_chan_in[MAX_LEN];
+ char last_nick_in[MAX_LEN];
+ char last_chans_out[MAX_LEN];
+ int default_destination;
+ int show_prefix;
+ int show_nick_prefix;
+ int with_host;
+ int filter;
+ int prune;
+ int command_to_event;
};
typedef struct arguments irc_ctx_t;
@@ -172,7 +180,137 @@ typedef struct arguments irc_ctx_t;
/* The arguments */
struct arguments args;
+void initialize_args()
+{
+ args.nick = "irctk";
+ args.server = NULL;
+ args.port = 6667;
+ args.channels = (char**) NULL;
+ args.n_channels = 0;
+ args.interval = isatty(fileno(stdin))?0:1000000;
+ args.verbosity = 0;
+ args.with_host = 0;
+ args.filter = 0;
+ args.prune = 0;
+ args.command_to_event = 1;
+ args.own = 0;
+ args.last_chan_in[0] = 0;
+ args.last_nick_in[0] = 0;
+ args.last_chans_out[0] = 0;
+ args.default_destination = DEFAULT_LAST_IN;
+ args.show_prefix = 0;
+}
+
+
+
+
+static error_t parse_opt (int key, char *arg, struct argp_state *state)
+{
+ struct arguments *arguments = state->input;
+ int i;
+
+ if (key != ARGP_KEY_ARG && key != ARGP_KEY_END && (! arguments->channels))
+ {
+ switch (key)
+ {
+ case 'v':
+ arguments->verbosity = 1;
+ break;
+ case 'q':
+ arguments->verbosity = -1;
+ break;
+ case 'i':
+ arguments->interval = (int) (atof(arg) * 1000000.);
+ break;
+ case 'o':
+ arguments->own = 1;
+ break;
+ case 'w':
+ arguments->with_host = 1;
+ break;
+ case 'r':
+ arguments->show_nick_prefix = 1;
+ break;
+ case '0':
+ arguments->default_destination = DEFAULT_FIRST;
+ break;
+ case 'f':
+ arguments->filter = 1;
+ break;
+ case 'F':
+ arguments->filter = 1;
+ arguments->prune = 1;
+ break;
+ case 'a':
+ arguments->default_destination = DEFAULT_LAST_IN;
+ break;
+ case 'p':
+ arguments->default_destination = DEFAULT_LAST_OUT;
+ break;
+ case 'l':
+ arguments->default_destination = DEFAULT_ALL;
+ break;
+ case 'P':
+ arguments->show_prefix = 1;
+ break;
+
+ case ARGP_KEY_NO_ARGS:
+ argp_usage (state);
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ } else {
+ switch(key)
+ {
+ /* TODO shouldn't allow options when a channel was seen */
+ case ARGP_KEY_ARG:
+ //debug("saw an arg");
+ if (state->arg_num == 0)
+ {
+ i = -1;
+ arguments->raw_dest = arg;
+ arguments->server = arg;
+ while (arguments->raw_dest[++i])
+ {
+ if (arguments->raw_dest[i] == '@')
+ {
+ arguments->raw_dest[i] = 0;
+ arguments->nick = arguments->raw_dest;
+ arguments->server = arguments->raw_dest + i + 1;
+ }
+ if (arguments->raw_dest[i] == ':')
+ {
+ arguments->raw_dest[i] = 0;
+ arguments->port = atoi(arguments->raw_dest + i + 1);
+ }
+ }
+ }
+ else {
+ if (arguments->channels == NULL)
+ {
+ //debug("start with %s, at %d", arg, state->arg_num);
+ arguments->channels = state->argv + (state->next - 1);
+ }
+ arguments->n_channels++;
+ }
+ break;
+
+ case ARGP_KEY_END:
+ if (state->arg_num < 1)
+ /* TODO rather test if server is still null */
+ argp_usage (state);
+ break;
+ }
+
+ }
+ return 0;
+}
+
+static struct argp argp = { options, parse_opt, args_doc, doc };
+
+/* TODO2 refactor those 3 */
void info(const char *err, ...)
{
va_list ap;
@@ -191,55 +329,33 @@ void debug(const char *err, ...)
va_start(ap, err);
if (args.verbosity > 0)
{
- /* TODO refactor with info */
fprintf(stderr, "debug: ");
vfprintf(stderr, err, ap);
fprintf(stderr, "\n");
}
}
-void debug_args()
-{
- debug("n_channels = %d\ninterval = %d\nnick = %s\nserver = %s\nport = %d\n",
- args.n_channels, args.interval, args.nick, args.server, args.port);
-}
-
-void initialize_args()
-{
-
- args.verbosity = 0;
- args.with_host = 0;
- args.filter = 0;
- args.prune = 0;
- debug("coucou1");
- debug_args(); // TODO this is debug
- args.n_channels = 0;
- debug("coucou2");
- debug_args(); // TODO this is debug
- args.channels = (char**) NULL;
- args.interval = isatty(fileno(stdin))?0:1000000;
- args.own = 0;
- args.nick = "irctk";
- args.port = 6667;
- args.last_chan_in[0] = 0;
- args.last_nick_in[0] = 0;
- args.last_chans_out[0] = 0;
- args.default_destination = DEFAULT_LAST_IN;
- args.show_prefix = 0;
- debug("coucou");
- debug_args(); // TODO this is debug
-}
void die(int val, const char *err, ...)
{
- /* never die, always retry with info messages */
+ /* TODO avoid dying, rather retry with info messages */
va_list ap;
va_start(ap, err);
- fprintf(stderr, "Error: ");
+ fprintf(stderr, "error: ");
vfprintf(stderr, err, ap);
fprintf(stderr, "\n");
exit(val);
}
+void debug_args()
+{
+ debug("n_channels = %d\ninterval = %d\nnick = %s\nserver = %s\nport = %d\n",
+ args.n_channels, args.interval, args.nick, args.server, args.port);
+}
+
+
+
+
+
char* first_chan()
{
@@ -250,16 +366,49 @@ char* first_chan()
int do_cmd_msg(irc_session_t *s, const char* chan, const char* line)
{
- int rsl;
- /* TODO ask the server to notify, if possible */
- /* TODO find a way to get real host name (part after !) */
+ int rsl = -1;
+
+ /* TODOponey ask the server to notify, if possible */
+ /* TODO2 find a way to get real host name (part after !) */
- rsl = irc_cmd_msg (s, chan, line);
+ /* TODO2 provide a means to escape '/' */
+ if (line[0] == '/' && args.command_to_event) {
+ if ( strstr (line[1], "nick ") == line[1] )
+ {
+ rsl = irc_cmd_nick (s, line+6);
+ } else if (strstr (line[1], "part") == line[1]) {
+ if (!line[5] || line[5] == '\n')
+ {
+ rsl = irc_cmd_part(s, chan);
+ } else if (line[5] == ' ') {
+ rsl = irc_cmd_part(s, line + 6);
+ }
+ } else if (strstr (line[1], "join") == line[1]) {
+ if (!line[5] || line[5] == '\n')
+ {
+ rsl = irc_cmd_join(s, chan, NULL);
+ } else if (line[5] == ' ') {
+ rsl = irc_cmd_join(s, line + 6, NULL);
+ }
+ } else if (strstr (line[1], "quit") == line[1]) {
+ /* TODO notify main thread that it is over */
+ if (!line[5] || line[5] == '\n')
+ {
+ rsl = irc_cmd_quit(s, NULL);
+ } else if (line[5] == ' ') {
+ rsl = irc_cmd_quit(s, line + 6);
+ }
+ }
+ } else {
+ rsl = irc_cmd_msg (s, chan, line);
+ }
/* TODO manage errors */
if (rsl)
return rsl;
+
if (args.own)
{
+ /* TODO join, quit, etc. take place in a special '[]' channel */
printf("[%s] <%s> %s", chan, args.nick, line);
fflush(stdout);
}
@@ -306,6 +455,11 @@ int cmd_msg(irc_session_t *s, char* target, const char* line)
case DEFAULT_LAST_OUT:
target = args.last_chans_out;
break;
+
+ case DEFAULT_ALL:
+ /* TODO */
+ target = args.last_chans_out;
+ break;
}
}
@@ -330,119 +484,6 @@ int cmd_msg(irc_session_t *s, char* target, const char* line)
return rsl;
}
-
-
-/* Parse a single option. */
- static error_t
-parse_opt (int key, char *arg, struct argp_state *state)
-{
- /* Get the input argument from argp_parse, which we
- know is a pointer to our arguments structure. */
- struct arguments *arguments = state->input;
- int i;
-
- if (key != ARGP_KEY_ARG && key != ARGP_KEY_END && (! arguments->channels))
- {
- switch (key)
- {
- case 'v':
- arguments->verbosity = 1;
- break;
- case 'q':
- arguments->verbosity = -1;
- break;
- case 'i':
- // TODO use float, and be more robust
- arguments->interval = (int) (atof(arg) * 1000000.);
- debug ("seen i, nchan is %d, took value %d", arguments->n_channels, arguments->interval);
- break;
- case 'o':
- arguments->own = 1;
- break;
- case 'w':
- arguments->with_host = 1;
- break;
- case 'r':
- arguments->show_nick_prefix = 1;
- break;
- case '0':
- arguments->default_destination = DEFAULT_FIRST;
- break;
- case 'f':
- arguments->filter = 1;
- break;
- case 'F':
- arguments->filter = 1;
- arguments->prune = 1;
- break;
- case 'a':
- arguments->default_destination = DEFAULT_LAST_IN;
- break;
- case 'p':
- arguments->default_destination = DEFAULT_LAST_OUT;
- break;
- case 'P':
- arguments->show_prefix = 1;
- break;
-
- case ARGP_KEY_NO_ARGS:
- argp_usage (state);
-
- default:
- return ARGP_ERR_UNKNOWN;
- }
- } else {
- switch(key)
- {
- /* TODO option exclusion doesn't work! */
- case ARGP_KEY_ARG:
- debug("saw an arg");
- if (state->arg_num == 0)
- {
- i = -1;
- arguments->raw_dest = arg;
- arguments->server = arg;
- while (arguments->raw_dest[++i])
- {
- if (arguments->raw_dest[i] == '@')
- {
- arguments->raw_dest[i] = 0;
- arguments->nick = arguments->raw_dest;
- arguments->server = arguments->raw_dest + i + 1;
- }
- if (arguments->raw_dest[i] == ':')
- {
- arguments->raw_dest[i] = 0;
- arguments->port = atoi(arguments->raw_dest + i + 1);
- }
- }
- }
- else {
- if (arguments->channels == NULL)
- {
- debug("start with %s, at %d", arg, state->arg_num);
- arguments->channels = state->argv + (state->next - 1);
- }
- arguments->n_channels++;
- }
- break;
-
- case ARGP_KEY_END:
- if (state->arg_num < 1)
- /* Not enough arguments. */
- argp_usage (state);
- break;
- }
-
- }
- return 0;
-}
-
-/* Our argp parser. */
-static struct argp argp = { options, parse_opt, args_doc, doc };
-
-
-
THREAD_FUNCTION(irc_listen)
{
irc_session_t * sp = (irc_session_t *) arg;
@@ -630,14 +671,6 @@ void event_channel (irc_session_t * session, const char * event, const char * or
/*irc_target_get_nick (origin, nickbuf, sizeof(nickbuf));
- if ( !strcmp (params[1], "quit") )
- irc_cmd_quit (session, "of course, Master!");
-
- if ( !strcmp (params[1], "help") )
- {
- irc_cmd_msg (session, params[0], "quit, help, dcc chat, dcc send, ctcp");
- }
-
if ( !strcmp (params[1], "ctcp") )
{
irc_cmd_ctcp_request (session, nickbuf, "PING 223");
@@ -668,9 +701,6 @@ void event_channel (irc_session_t * session, const char * event, const char * or
if ( strstr (params[1], "mode ") == params[1] )
irc_cmd_channel_mode (session, params[0], params[1] + 5);
- if ( strstr (params[1], "nick ") == params[1] )
- irc_cmd_nick (session, params[1] + 5);
-
if ( strstr (params[1], "whois ") == params[1] )
irc_cmd_whois (session, params[1] + 5);*/
}
@@ -874,16 +904,17 @@ int start ()
int main (int argc, char **argv)
{
- /* Default values. */
initialize_args();
- debug_args();
+ //debug_args();
argp_parse (&argp, argc, argv, 0, 0, &args);
strcpy(args.last_chan_in, first_chan());
strcpy(args.last_chans_out, first_chan());
- debug_args();
+ //debug_args();
return start();
}
+
+