commit 1144bd75047abbcbda779e8b3e28a34904d50363
parent 0c62375e3f62420a2e488f2f7ce072ce6d88dd10
Author: Antoine Amarilli <ant.amarilli@free.fr>
Date: Sun, 20 Feb 2011 03:25:26 +0100
done some cleanup, added non-functional -N, reconnect works
Diffstat:
irctk.c | | | 230 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
1 file changed, 130 insertions(+), 100 deletions(-)
diff --git a/irctk.c b/irctk.c
@@ -24,12 +24,13 @@
#define _GNU_SOURCE
// TODO cli options for that
-#define INITIAL_RETRY 15
+#define INITIAL_RETRY 5
#define FACTOR_RETRY 2
#define E_SESSION 1
#define E_CONNECT 2
#define E_THREAD 3
+#define E_BADNAME 4
#define DEFAULT_FIRST 0
#define DEFAULT_LAST_IN 1
@@ -43,9 +44,7 @@
// TODO get rid of that
#define MAX_LEN 4096
-// TODO pseudo tracking
-
-// TODO default username is login pruned of bad chars
+// TODO tracking of nicks
//TODO const char *argp_program_version = "irctk 0.1";
//TODO const char *argp_program_bug_address = "<a3nm@a3nm.net>";
@@ -74,39 +73,23 @@ static struct argp_option options[] = {
"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,
- "Don't generate events from messages with \"/quit\", \"/me\"...",
- PARSING, }, // TODO
- {"no-destination-prefix", 0, 0, 0,
- "Don't look for []",
- PARSING}, // TODO */
- {"event-to-nothing", 'n', 0, 0,
- "Ignore server events (default).",
- PARSING},
- {"event-to-command", 'c', 0, 0,
- "Translate server events to messages with \"/quit\", \"/me\"...",
- PARSING},
- {"event-to-message", 'm', 0, 0,
- "Translate server events to a human-readable description",
- PARSING},
- {"with-host", 'w', 0, 0,
- "Keep the host info in pseudos" ,
- DISPLAY_SELECTION},
- /* TODO test, and 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)",
/* TODOponey ideally should not delay for bots, only for things piped, is there a
* better way such as only waiting at the end? */
MISC},
- {"username", 'U', "name", 0,
- "Unix username (default: irctk)",
- NAME},
- {"realname", 'R', "name", 0,
- "Full name (default: irctk)",
- NAME},
+ /*{"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*/
+
+ {"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 }, // TODO
+ /*{"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 },
+ */
+
{"default-always-first", '0', 0, 0,
"Post messages to the first specified channel by default",
CHANNEL_SELECTION},
@@ -122,13 +105,7 @@ static struct argp_option options[] = {
{"show-inferred", 'P', 0, 0,
"When inferring a next chan with --default-last-posted, display it on stderr",
CHANNEL_SELECTION},
- {"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-argv", 'E', 0, 0,
- "Run this command on each message, passing the channel, nick and message as $1, $2, and $3", COM_MODE },
- */
+
{"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 indicates the end of an answer)", BOT_OPTIONS },
/* TODO externalize those two features as a wrapper script */
@@ -136,8 +113,41 @@ static struct argp_option options[] = {
"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 }, // TODO*/
+
+ {"with-host", 'w', 0, 0,
+ "Keep the host info in pseudos" ,
+ DISPLAY_SELECTION},
+ /* TODO test, and make compatible with --own */
+ {"own", 'o', 0, 0,
+ "Also display messages posted by self",
+ DISPLAY_SELECTION},
+
+ /*{"no-command-to-event", 0, 0, 0,
+ "Don't generate events from messages with \"/quit\", \"/me\"...",
+ PARSING, }, // TODO
+ {"no-destination-prefix", 0, 0, 0,
+ "Don't look for []",
+ PARSING}, // TODO */
+ {"event-to-nothing", 'n', 0, 0,
+ "Ignore server events (default).",
+ PARSING},
+ {"event-to-command", 'c', 0, 0,
+ "Translate server events to messages with \"/quit\", \"/me\"...",
+ PARSING},
+ {"event-to-message", 'm', 0, 0,
+ "Translate server events to a human-readable description",
+ PARSING},
+
+ {"username", 'U', "name", 0,
+ "Unix username (default: irctk)",
+ NAME},
+ {"realname", 'R', "name", 0,
+ "Full name (default: irctk)",
+ NAME},
+ {"force-nick", 'N', 0, 0, //TODO
+ "Don't give up if the nick is invalid (revert to default) or already taken (add trailing underscores)",
+ NAME},
+
{ 0 }
};
@@ -147,29 +157,38 @@ static struct argp_option options[] = {
struct arguments
{
char *nick;
- char *username;
- char *realname;
char *server;
int port;
char **channels;
int n_channels;
- int interval;
+
int verbosity;
- int command;
+
+ int interval;
+
+ int default_destination;
+ int show_inferred;
+
+ int with_host;
int own;
+
+ int event_to;
+
+ char *username;
+ int username_set; // to get nick as default username
+ char *realname;
+ int force_nick;
+
+ int command;
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;
- int event_to;
};
typedef struct arguments irc_ctx_t;
@@ -184,21 +203,30 @@ void initialize_args()
args.port = 6667;
args.channels = (char**) NULL;
args.n_channels = 0;
- args.interval = isatty(fileno(stdin))?0:1000000;
+
args.verbosity = 0;
+
+ args.interval = isatty(fileno(stdin))?0:1000000;
+
+ args.default_destination = DEFAULT_LAST_IN;
+ args.show_inferred = 0;
+
args.with_host = 0;
+ args.own = 0;
+
+ args.event_to = NOTHING;
+
+ args.username_set = 0;
+ args.username = args.nick;
+ args.realname = "irctk";
+ args.force_nick = 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;
- args.event_to = NOTHING;
- args.username = "irctk";
- args.realname = "irctk";
+ args.command_to_event = 1;
}
@@ -232,6 +260,7 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
arguments->interval = (int) (atof(arg) * 1000000.);
break;
case 'U':
+ arguments->username_set = 1;
arguments->username = arg;
break;
case 'R':
@@ -266,7 +295,10 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
arguments->default_destination = DEFAULT_ALL;
break;
case 'P':
- arguments->show_prefix = 1;
+ arguments->show_inferred = 1;
+ break;
+ case 'N':
+ arguments->force_nick = 1;
break;
case ARGP_KEY_NO_ARGS:
@@ -278,9 +310,7 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
} 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;
@@ -292,6 +322,8 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
{
arguments->raw_dest[i] = 0;
arguments->nick = arguments->raw_dest;
+ if (!arguments->username_set)
+ arguments->username = arguments->raw_dest;
arguments->server = arguments->raw_dest + i + 1;
}
if (arguments->raw_dest[i] == ':')
@@ -508,17 +540,16 @@ int cmd_msg(irc_session_t *s, char* target, const char* line)
THREAD_FUNCTION(irc_listen)
{
- irc_session_t * sp = (irc_session_t *) arg;
-
- irc_run(sp);
-
- return 0;
+ irc_session_t * sp = (irc_session_t *) arg;
+ irc_run(sp);
+ return 0;
}
void dump_event (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
{
char buf[512]; // TODO danger
int cnt;
+ int rsl;
buf[0] = '\0';
@@ -530,6 +561,21 @@ void dump_event (irc_session_t * session, const char * event, const char * origi
strcat (buf, params[cnt]);
}
+ if (!strcmp(event, "432"))
+ {
+ /* bad nick */
+ if (args.force_nick)
+ {
+ // TODO does not work
+ info("Invalid nick, reverting to \"irctk\"");
+ args.nick = "irctk";
+ rsl = irc_cmd_nick (session, "irctk");
+ } else {
+ // TODO abort
+ die(E_BADNAME, "Invalid nick!");
+ }
+ }
+
debug("Event \"%s\", origin: \"%s\", params: %d [%s]", event, origin ? origin : "NULL", cnt, buf);
}
@@ -842,7 +888,7 @@ irc_session_t* do_connect()
irc_set_ctx (s, &args);
debug_args();
- debug("Trying to connect to %s port %d with nick %s...",
+ debug("Connecting to %s port %d with nick %s...",
args.server, args.port, args.nick);
@@ -852,7 +898,7 @@ irc_session_t* do_connect()
return s;
}
-int start ()
+int start (int max_wait)
{
irc_session_t * s;
thread_id_t tid;
@@ -862,13 +908,12 @@ int start ()
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...");
+ debug("Starting thread...");
if (CREATE_THREAD (&tid, irc_listen, s))
die(E_THREAD, "CREATE_THREAD failed: %s", strerror(errno)); // TODO spurious \n
@@ -877,57 +922,42 @@ int start ()
line = (char*) malloc(size+1);
- if (args.show_prefix && args.default_destination == DEFAULT_LAST_OUT)
+ if (args.show_inferred && args.default_destination == DEFAULT_LAST_OUT)
fprintf(stderr, "[%s] ", args.last_chans_out);
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)
+ if (!args.ready)
{
waiting = 0;
debug("Waiting for the connection to be ready...");
while (waiting < max_wait && !args.ready)
{
- debug("waiting");
+ debug("waiting (%d)", 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();
+ if (!args.ready) {
+ debug("nick is %s\n", args.nick);
+ info("Connection timed out after %d seconds, retrying...", max_wait);
+ irc_disconnect(s);
+ args.ready = 0;
+ sleep(1);
+ return start(max_wait * FACTOR_RETRY);
+ }
}
while ( (res = getline((char**) &line, (size_t*) &size, stdin)) != -1 )
{
debug("startloop : got %s, waiting", line);
- while (!args.ready)
+ if (!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();
+ info("Connection lost, reconnecting...");
+ return start(max_wait);
}
debug("ready", line);
@@ -960,7 +990,7 @@ int start ()
cmd_msg(s, "", line);
}
- if (args.show_prefix && args.default_destination == DEFAULT_LAST_OUT)
+ if (args.show_inferred && args.default_destination == DEFAULT_LAST_OUT)
fprintf(stderr, "[%s] ", args.last_chans_out);
usleep(args.interval);
@@ -989,7 +1019,7 @@ int main (int argc, char **argv)
//debug_args();
- return start();
+ return start(INITIAL_RETRY);
}