commit 8bfc9b7f08c5fc3e00fdcec7c3ce034250a98adc
parent a8f487c9aaacb51f252ab46641ce0ddcc0ae96a2
Author: Antoine Amarilli <ant.amarilli@free.fr>
Date: Sun, 16 Jan 2011 13:44:22 +0100
more help, ordered help, more options, buggy auto-reconnect
Diffstat:
Makefile | | | 8 | ++++---- |
irctk.c | | | 235 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- |
2 files changed, 180 insertions(+), 63 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,8 +1,8 @@
# $Id: Makefile.in 42 2004-10-10 16:16:15Z gyunaev $
CC = gcc
CXX = g++
-CFLAGS = -Wall -O3 -DENABLE_THREADS -D_REENTRANT
-LIBS = ../src/libircclient.a -lpthread -lnsl
+CFLAGS = -Wall -g -DENABLE_THREADS -D_REENTRANT
+LIBS = /usr/lib/libircclient.a -lpthread -lnsl
INCLUDES=-I../include
EXAMPLES=irctk
@@ -21,8 +21,8 @@ distclean: clean
.c.o:
@echo "Compiling $<"
- @$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
+ $(CC) $(CFLAGS) $(INCLUDES) -c -o $@ $<
.cpp.o:
@echo "Compiling $<"
- @$(CXX) $(CFLAGS) $(INCLUDES) -c -o $@ $<
+ $(CXX) $(CFLAGS) $(INCLUDES) -c -o $@ $<
diff --git a/irctk.c b/irctk.c
@@ -32,6 +32,8 @@
#include <stdlib.h>
#include <errno.h>
#include <argp.h>
+#include <unistd.h>
+#include <sys/time.h>
#include "libircclient.h"
@@ -43,6 +45,9 @@
#define thread_id_t pthread_t
#define _GNU_SOURCE
+#define INITIAL_RETRY 3
+#define FACTOR_RETRY 2
+
#define E_SESSION 1
#define E_CONNECT 2
#define E_THREAD 3
@@ -53,8 +58,10 @@
// TODO
#define MAX_LEN 1024
-const char *argp_program_version = "irctk 0.1";
-const char *argp_program_bug_address = "<a3nm@a3nm.net>";
+//const char *argp_program_version = "irctk 0.1";
+//const char *argp_program_bug_address = "<a3nm@a3nm.net>";
+const char *argp_program_version = NULL;
+const char *argp_program_bug_address = NULL;
/* Program documentation. */
static char doc[] =
@@ -63,51 +70,70 @@ static char doc[] =
/* A description of the arguments we accept. */
static char args_doc[] = "[NICK@]SERVER[:PORT] [CHANNEL]...";
+#define STANDARD 0
+#define MISC 1
+#define COM_MODE 2
+#define CHANNEL_SELECTION 3
+#define BOT_OPTIONS 4
+#define DISPLAY_SELECTION 5
+#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" },
+ "Produce debug output on stderr", STANDARD, },
{"quiet", 'q', 0, 0,
- "Don't even display errors on stderr, fail silently" },
+ "Don't even display errors on stderr, fail silently", STANDARD, },
{"no-command-to-event", 0, 0, 0,
- "Don't generate events from messages with \"/quit\", \"/me\"..." }, /* TODO */
+ "Don't generate events from messages with \"/quit\", \"/me\"...",
+ PARSING, }, /* TODO */
{"no-destination-prefix", 0, 0, 0,
- "Don't look for []" }, /* TODO */
+ "Don't look for []",
+ PARSING}, /* TODO */
{"event-to-command", 'c', 0, 0,
- "Translate server events to messages with \"/quit\", \"/me\"..." }, /* TODO */
+ "Translate server events to messages with \"/quit\", \"/me\"...",
+ PARSING}, /* TODO */
{"event-to-message", 'm', 0, 0,
- "Translate server events to a human-readable description" }, /* TODO */
+ "Translate server events to a human-readable description",
+ PARSING}, /* TODO */
{"with-host", 'w', 0, 0,
- "Keep the host info in pseudos" },
+ "Keep the host info in pseudos" , /* TODO use irc_stripnick */
+ DISPLAY_SELECTION},
/* TODO, and make compatible with --own */
{"own", 'o', 0, 0,
- "Also display messages posted by self" },
+ "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 detect if stdin is a tty for delay configuration */
+ "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
+ * better way such as only waiting at the end? */
+ MISC},
{"default-always-first", 'f', 0, 0,
- "Post messages to the first specified channel by default" },
+ "Post messages to the first specified channel by default",
+ CHANNEL_SELECTION},
{"default-last-active", 'a', 0, 0,
- "Post messages to the last active channel by default" },
+ "Post messages to the last active channel by default (default)",
+ CHANNEL_SELECTION},
{"default-last-posted", 'p', 0, 0,
- "Post messages to the last posted channel by default" },
+ "Post messages to the last posted channel by default",
+ CHANNEL_SELECTION},
{"show-inferred", 'P', 0, 0,
- "When inferring a next chan with --default-last-posted, display it on stderr" },
+ "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, blank line-terminated answer on stdin to all lines passed on stdout, and will bufferize activity before that" },
+ "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" }, /* TODO and support several of them */
+ "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" },
+ "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, also infer a destination nick, and prefix lines with this nick" },
+ "When inferring a destination channel automatically, also infer a destination nick, and prefix lines with this nick", BOT_OPTIONS },
{"filter", 'f', 0, 0,
- "Only keep messages directly addressed to us (in private channel or with lines prefixed by our nick)" },
+ "Only keep messages directly addressed to us (in private channel or with lines prefixed by our nick)", 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)" },
+ "Refuse to send any message to channels not specified on the command line (default is to join as needed)", MISC },
{ 0 }
};
@@ -119,7 +145,8 @@ struct arguments
char ** channels;
int n_channels;
int interval;
- int verbose;
+ int verbosity;
+ int quiet;
int command;
char * nick;
char * server;
@@ -138,12 +165,48 @@ typedef struct arguments irc_ctx_t;
/* The arguments */
struct arguments args;
+
+void info(const char *err, ...)
+{
+ va_list ap;
+ va_start(ap, err);
+ if (args.verbosity >= 0)
+ {
+ fprintf(stderr, "info: ");
+ vfprintf(stderr, err, ap);
+ fprintf(stderr, "\n");
+ }
+}
+
+void debug(const char *err, ...)
+{
+ va_list ap;
+ 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;
+ 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.verbose = 0;
- args.interval = isatty(fileno(stdin))?0:1;
+ args.interval = isatty(fileno(stdin))?0:1000000;
args.own = 0;
args.nick = "irctk";
args.port = 6667;
@@ -151,10 +214,13 @@ void initialize_args()
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 */
va_list ap;
va_start(ap, err);
fprintf(stderr, "Error: ");
@@ -164,18 +230,6 @@ void die(int val, const char *err, ...)
}
-void debug(const char *err, ...)
-{
- va_list ap;
- va_start(ap, err);
- if (args.verbose)
- {
- fprintf(stderr, "debug: ");
- vfprintf(stderr, err, ap);
- fprintf(stderr, "\n");
- }
-}
-
char* first_chan()
{
if (args.n_channels)
@@ -266,12 +320,15 @@ parse_opt (int key, char *arg, struct argp_state *state)
switch (key)
{
case 'v':
- arguments->verbose = 1;
+ arguments->verbosity = 1;
+ break;
+ case 'q':
+ arguments->verbosity = -1;
break;
case 'i':
// TODO use float, and be more robust
- debug ("seen i, nchan is %d", arguments->n_channels);
- arguments->interval = atoi(arg);
+ 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;
@@ -371,7 +428,6 @@ void dump_event (irc_session_t * session, const char * event, const char * origi
strcat (buf, params[cnt]);
}
-
debug("Event \"%s\", origin: \"%s\", params: %d [%s]", event, origin ? origin : "NULL", cnt, buf);
}
@@ -382,6 +438,9 @@ void event_join (irc_session_t * session, const char * event, const char * origi
irc_cmd_user_mode (session, "+i");
debug("Joined!");
+
+ /* Check for that before talking */
+
/*irc_ctx_t * ctx = (irc_ctx_t *) irc_get_ctx (session);
if ( !origin )
@@ -569,15 +628,10 @@ void event_numeric (irc_session_t * session, unsigned int event, const char * or
dump_event (session, buf, origin, params, count);
}
-
-int start ()
+irc_session_t* do_connect()
{
+ irc_session_t *s;
irc_callbacks_t callbacks;
- irc_session_t * s;
- thread_id_t tid;
- char *line = NULL;
- int res, size=100;
-
memset (&callbacks, 0, sizeof(callbacks));
callbacks.event_connect = event_connect;
@@ -608,12 +662,31 @@ int start ()
irc_set_ctx (s, &args);
+ debug_args();
debug("Trying to connect to %s port %d with nick %s...",
args.server, args.port, args.nick);
+
if (irc_connect (s, args.server, args.port, 0, args.nick, 0, 0))
die(E_CONNECT, "Could not connect: %s\n", irc_strerror (irc_errno(s)));
+ return s;
+}
+
+int start ()
+{
+ irc_session_t * s;
+ thread_id_t tid;
+ char *line = NULL;
+ int res, size=100;
+ struct timeval tp1, tp2;
+ long tp;
+ int first = 1;
+ int waiting = 0;
+ int max_wait = INITIAL_RETRY;
+
+ s = do_connect();
+
debug("Connection request successful!");
debug("Trying to create thread...");
@@ -628,17 +701,63 @@ int start ()
if (args.show_prefix && args.default_destination == DEFAULT_LAST_OUT)
fprintf(stderr, "[%s] ", args.last_chans_out);
- while ( (res = getline((char**) &line, (size_t*) &size, stdin)) != -1 )
+ gettimeofday(&tp1, NULL);
+
+ /* this is here early in order to get the connection working asap
+ * TODO refactor it with the other copy! */
+ /* TODO THIS DOESN't WORK and INTRODUCES DELAYS! */
+ while (!args.ready)
{
- while (!args.ready)
+ waiting = 0;
+ debug("Waiting for the connection to be ready...");
+ while (waiting < max_wait)
{
- debug("Waiting for the connection to be ready...");
+ debug("waiting");
// TODO manage timeouts, try reconnects, handle errors, etc.
// TODO manage duplicate pseudos
sleep(1);
+ waiting++;
}
- debug("got %s", line);
+ if (args.ready) break;
+ max_wait *= FACTOR_RETRY;
+ info("Trying to reconnect for %d seconds...", max_wait);
+ irc_disconnect(s);
+ args.ready = 0;
+ sleep(1);
+ s = do_connect();
+ }
+ while ( (res = getline((char**) &line, (size_t*) &size, stdin)) != -1 )
+ {
+ debug("got %s, waiting", line);
+ while (!args.ready)
+ {
+ waiting = 0;
+ debug("Waiting for connection");
+ while (waiting < max_wait)
+ {
+ debug("Waiting");
+ // TODO manage timeouts, try reconnects, handle errors, etc.
+ // TODO manage duplicate pseudos
+ sleep(1);
+ waiting++;
+ }
+ if (args.ready) break;
+ max_wait *= FACTOR_RETRY;
+ info("Trying to reconnect for %d seconds...", max_wait);
+ irc_disconnect(s);
+ args.ready = 0;
+ sleep(1);
+ s = do_connect();
+ }
+
+ debug("ready", line);
+
+ gettimeofday(&tp2, NULL);
+ tp = 1000000*(tp2.tv_sec - tp1.tv_sec) + tp2.tv_usec - tp1.tv_usec;
+ if (tp < args.interval && !first)
+ usleep(args.interval - tp);
+ first = 0;
if (line[0] == '[')
{
@@ -659,11 +778,11 @@ int start ()
if (args.show_prefix && args.default_destination == DEFAULT_LAST_OUT)
fprintf(stderr, "[%s] ", args.last_chans_out);
- sleep(args.interval);
+ usleep(args.interval);
}
line = NULL;
- sleep(args.interval);
+ usleep(2*args.interval);
irc_disconnect(s);
free(line);
@@ -675,15 +794,13 @@ int main (int argc, char **argv)
/* Default values. */
initialize_args();
- debug ("isatty? %s\n", isatty(fileno(stdin))?"yes":"no");
-
+ 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("n_channels = %d\ninterval = %d\nnick = %s\nserver = %s\nport = %d\n",
- args.n_channels, args.interval, args.nick, args.server, args.port);
+
+ debug_args();
return start();
}