commit 182d990623383bb7573607ef4fc02c7df34edc15
parent a719be5a9881c0e1a4257752ad0861e526db9bb1
Author: Antoine Amarilli <a3nm@a3nm.net>
Date: Sat, 16 Jun 2012 18:14:25 +0200
loads of cleanup
Diffstat:
README | | | 6 | +++--- |
irctk.c | | | 411 | ++++++++++++++++++++++++++++++++++++++++++++----------------------------------- |
2 files changed, 230 insertions(+), 187 deletions(-)
diff --git a/README b/README
@@ -2,14 +2,14 @@ irctk is a general-purpose IRC wrapper. It connects to an IRC server specified
as [NICK@]SERVER[:PORT] as a CLI argument, posts what it receives from stdin and
displays what is said to stdout.
-Beware, this code is not yet secure or clean. I have been using it regularly for
-some time, but your needs might be different from mine.
-
irctk is not related to IrcTK by Max Countryman
<https://github.com/maxcountryman/irctk>.
To compile, you need libircclient 1.6 <http://www.ulduzsoft.com/libircclient/>.
+Warning, the code has not been thoroughly audited. SSL support does not really
+work, and any certificates will be accepted.
+
TODO these examples aren't secure
TODO use -m -c -n
diff --git a/irctk.c b/irctk.c
@@ -4,26 +4,19 @@
*/
-#include <stdio.h>
+#include <argp.h>
+#include <errno.h>
+#include <pthread.h>
#include <stdarg.h>
-#include <string.h>
+#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
-#include <argp.h>
-#include <unistd.h>
+#include <string.h>
#include <sys/time.h>
+#include <unistd.h>
#include <libircclient/libircclient.h>
#include <libircclient/libirc_rfcnumeric.h>
-#include <unistd.h>
-#include <pthread.h>
-
-#define CREATE_THREAD(id,func,param) (pthread_create (id, 0, func, (void *) param) != 0)
-#define THREAD_FUNCTION(funcname) static void * funcname (void * arg)
-#define thread_id_t pthread_t
-#define _GNU_SOURCE
-
#define E_SESSION 1
#define E_CONNECT 2
#define E_THREAD 3
@@ -31,26 +24,23 @@
#define E_BADLINE 5
enum default_destinations {DEFAULT_FIRST, DEFAULT_LAST_IN, DEFAULT_LAST_OUT, DEFAULT_ALL};
-
enum event_tos {NOTHING, COMMAND, MESSAGE};
// TODO get rid of that
#define MAX_LEN 4096
#define MAX_NICK_LEN 4096
-// TODO tracking of nicks
+#define max(a, b) ((b) > (a) ? (b) : (a))
-//TODO const char *argp_program_version = "irctk 0.1";
-//TODO const char *argp_program_bug_address = "<a3nm@a3nm.net>";
-const char *argp_program_version = NULL;
-const char *argp_program_bug_address = NULL;
+const char *argp_program_version = "irctk 0.1";
+const char *argp_program_bug_address = "<a3nm@a3nm.net>";
/* Program documentation. */
static char doc[] =
"irctk -- an IRC toolkit";
/* A description of the arguments we accept. */
-static char args_doc[] = "[NICK[:PASSWORD]@]SERVER[:PORT] [CHANNEL]...";
+static char args_doc[] = "[NICK[:PASSWORD]@]SERVER[:PORT] [CHANNEL[:PASSWORD]]...";
#define STANDARD 0
#define MISC 1
@@ -60,27 +50,31 @@ static char args_doc[] = "[NICK[:PASSWORD]@]SERVER[:PORT] [CHANNEL]...";
#define DISPLAY_SELECTION 5
#define PARSING 6
#define NAME 7
+
/* The options we understand. */
static struct argp_option options[] = {
- {"verbose", 'v', 0, 0,
- "Produce debug output on stderr", STANDARD, },
- {"quiet", 'q', 0, 0,
- "Don't even display errors on stderr, fail silently", STANDARD, },
-
+ {"verbose", 'v', 0, 0,
+ "Produce debug output on stderr",
+ STANDARD},
+ {"quiet", 'q', 0, 0,
+ "Don't even display errors on stderr, fail silently",
+ STANDARD},
+
+ /* TODOponey ideally should not delay for bots, only for things piped, is there a
+ * better way such as only waiting at the end? */
{"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? */
+ "Wait delay between posted messages (default: 0 for tty stdin, 1 for"
+ " file/pipe)",
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*/
{"retry-after", 'y', "secs", 0,
"Wait delay before trying to reconnect (default: 5)",
MISC},
{"retry-factor", 'Y', "secs", 0,
"Retry delay multiplication factor after each failed attempt (default: 2)",
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*/
/*{"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*/
@@ -90,70 +84,78 @@ static struct argp_option options[] = {
"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,
+ {"default-always-first", '0', 0, 0,
"Post messages to the first specified channel by default",
- CHANNEL_SELECTION},
- {"default-last-active", 'a', 0, 0,
+ CHANNEL_SELECTION},
+ {"default-last-active", 'a', 0, 0,
"Post messages to the last active channel by default (default)",
- CHANNEL_SELECTION},
- {"default-last-posted", 'p', 0, 0,
+ CHANNEL_SELECTION},
+ {"default-last-posted", 'p', 0, 0,
"Post messages to the last posted channel by default",
- CHANNEL_SELECTION},
- {"default-all", 'l', 0, 0,
+ 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},
-
- {"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 },
+ CHANNEL_SELECTION},
+ {"show-inferred", 'P', 0, 0,
+ "When inferring a next chan with --default-last-posted, display it on"
+ " stderr",
+ CHANNEL_SELECTION},
+
+ {"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 */
- {"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 },
-
- {"with-host", 'w', 0, 0,
- "Keep the host info in pseudos" ,
- DISPLAY_SELECTION},
- /* TODO test, and make compatible with --own */
- {"own", 'o', 0, 0,
+ {"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 },
+
+ /* TODO test, and make compatible with --own */
+ {"with-host", 'w', 0, 0,
+ "Keep the host info in pseudos",
+ DISPLAY_SELECTION},
+ {"own", 'o', 0, 0,
"Also display messages posted by self",
- DISPLAY_SELECTION},
+ DISPLAY_SELECTION},
- /*{"no-command-to-event", 0, 0, 0,
- "Don't generate events from messages with \"/quit\", \"/me\"...",
- PARSING, }, */ // TODO
- {"no-destination-prefix", 'D', 0, 0,
+ {"no-destination-prefix", 'D', 0, 0,
"Don't look for []",
- PARSING},
- {"event-to-nothing", 'n', 0, 0,
+ PARSING},
+ {"event-to-nothing", 'n', 0, 0,
"Ignore server events (default).",
- PARSING},
- {"event-to-command", 'c', 0, 0,
+ PARSING},
+ {"event-to-command", 'c', 0, 0,
"Translate server events to messages with \"/quit\", \"/me\"...",
- PARSING},
- {"event-to-message", 'm', 0, 0,
+ PARSING},
+ {"event-to-message", 'm', 0, 0,
"Translate server events to a human-readable description",
- PARSING},
+ PARSING},
+ /*{"no-command-to-event", 0, 0, 0,
+ "Don't generate events from messages with \"/quit\", \"/me\"...",
+ PARSING, }, */ // TODO
{"username", 'U', "name", 0,
"Unix username (default: same as nick)",
- NAME},
+ NAME},
{"realname", 'R', "name", 0,
"Full name (default: same as nick)",
- NAME},
+ NAME},
{"force-nick", 'N', 0, 0,
- "Abort when the intended nick is unavailable or invalid instead of choosing another one",
- NAME},
+ "Abort when the intended nick is unavailable or invalid instead of picking"
+ " another one automatically",
+ NAME},
{ 0 }
};
-/*
- * We store data in IRC session context.
- */
+
+/* The structure to store program settings */
struct arguments
{
char nick[MAX_NICK_LEN];
@@ -198,9 +200,10 @@ struct arguments
typedef struct arguments irc_ctx_t;
-/* The arguments */
+/* The program settings */
struct arguments args;
+/* The initial argument values */
void initialize_args()
{
strncpy(args.nick, "irctk", MAX_NICK_LEN-1);
@@ -240,7 +243,9 @@ void initialize_args()
}
-void set_nick_and_names(struct arguments *arguments) {
+/* set our nick, and names if not already set */
+void set_nick_and_names(struct arguments *arguments)
+{
strncat(arguments->nick, arguments->raw_dest, MAX_NICK_LEN-1);
if (!arguments->username_set)
arguments->username = arguments->raw_dest;
@@ -249,6 +254,7 @@ void set_nick_and_names(struct arguments *arguments) {
}
+/* The command-line argument parsing function for argp */
static error_t parse_opt (int key, char *arg, struct argp_state *state)
{
struct arguments *arguments = state->input;
@@ -397,51 +403,57 @@ static error_t parse_opt (int key, char *arg, struct argp_state *state)
return 0;
}
+/* argp structure */
static struct argp argp = { options, parse_opt, args_doc, doc };
-/* TODO2 refactor those 3 */
-void info(const char *err, ...)
+/* Emit a message with a verbosity level, and optionally terminate.
+ * Verbosity is >=1 for debug, 0 for info, -n for error n-1 */
+void message(int verbosity, const char *err, va_list ap)
{
- va_list ap;
- va_start(ap, err);
- if (args.verbosity >= 0)
+ if (args.verbosity >= verbosity)
{
- fprintf(stderr, "info: ");
+ fprintf(stderr, "%s: ", verbosity > 0 ? "debug" :
+ verbosity >= 0 ? "info" : "error");
vfprintf(stderr, err, ap);
fprintf(stderr, "\n");
}
+ if (verbosity < 0)
+ exit(1-verbosity);
+}
+
+void info(const char *err, ...)
+{
+ va_list ap;
+ va_start(ap, err);
+ return message(0, err, ap);
}
void debug(const char *err, ...)
{
va_list ap;
va_start(ap, err);
- if (args.verbosity > 0)
- {
- fprintf(stderr, "debug: ");
- vfprintf(stderr, err, ap);
- fprintf(stderr, "\n");
- }
+ return message(1, err, ap);
}
void die(int val, const char *err, ...)
{
- /* TODO avoid dying, rather retry with info messages */
va_list ap;
va_start(ap, err);
- fprintf(stderr, "error: ");
- vfprintf(stderr, err, ap);
- fprintf(stderr, "\n");
- exit(val);
+ return message(-val - 1, err, ap);
}
+
void debug_args()
{
- debug("n_channels = %d\ninterval = %d\nnick = %s\nserver = %s\nport = %d\npw = %s\n",
- args.n_channels, args.interval, args.nick, args.server, args.port, args.password);
+ debug("n_channels = %d\ninterval = %d\nnick = %s\nserver = %s\nport = %d\n"
+ "pw = %s\n", args.n_channels, args.interval, args.nick, args.server,
+ args.port, args.password);
}
+
+/* Our main chan is either the first CLI chan or our own chan if there are no
+ * CLI chans */
char* first_chan()
{
if (args.n_channels)
@@ -449,7 +461,9 @@ char* first_chan()
else return args.nick;
}
-int join_channel(irc_session_t *s, char* chan) {
+/* Join a channel, optionally suffixed with :PASSWORD */
+int join_channel(irc_session_t *s, char* chan)
+{
char *password = chan;
int pos = strlen(password);
int ret;
@@ -468,9 +482,11 @@ int join_channel(irc_session_t *s, char* chan) {
return ret;
}
+/* Send a message or do a command */
int do_cmd_msg(irc_session_t *s, char* chan, char* line)
{
int rsl = -1;
+ int is_local = 1;
/* TODOponey ask the server to notify, if possible */
/* TODO2 find a way to get real host name (part after !) */
@@ -479,20 +495,20 @@ int do_cmd_msg(irc_session_t *s, char* chan, char* line)
join_channel (s, chan);
- // TODO also other commands (/kick, /topic...)
/* TODO2 provide a means to escape '/' */
if (line[0] == '/' && args.command_to_event) {
- if ( strstr (line + 1, "nick ") == line + 1 )
+ if (strstr(line + 1, "nick ") == line + 1 )
{
+ is_local = 0;
rsl = irc_cmd_nick (s, line+6);
- } else if (strstr (line + 1, "part") == line + 1) {
+ } 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) {
+ } else if (strstr(line + 1, "join") == line + 1) {
if (!line[5] || line[5] == '\n')
{
debug("join %s", chan);
@@ -501,18 +517,23 @@ int do_cmd_msg(irc_session_t *s, char* chan, char* line)
debug("join %s", line+6);
rsl = join_channel(s, line + 6);
}
- } else if (strstr (line + 1, "topic ") == line + 1) {
+ } else if (strstr(line + 1, "topic ") == line + 1) {
debug("topic %s", line+6);
rsl = irc_cmd_topic(s, chan, line + 6);
- } else if (strstr (line + 1, "quit") == line + 1) {
+ } else if (strstr(line + 1, "quit") == line + 1) {
/* TODO notify main thread that it is over */
+ is_local = 0;
if (!line[5] || line[5] == '\n')
{
rsl = irc_cmd_quit(s, NULL);
} else if (line[5] == ' ') {
rsl = irc_cmd_quit(s, line + 6);
}
- } // TODO: invite, names, list, topic, chanmode, kick, usermode, whois, raw
+ } else if (line[1] == ' ') {
+ // escaped message "/ /message"
+ rsl = irc_cmd_msg (s, chan, line + 2);
+ }
+ // TODO: invite, names, list, topic, chanmode, kick, usermode, whois, raw...
} else {
rsl = irc_cmd_msg (s, chan, line);
}
@@ -522,14 +543,14 @@ int do_cmd_msg(irc_session_t *s, char* chan, char* line)
if (args.own)
{
- /* TODO join, quit, etc. take place in a special '[]' channel */
- printf("[%s] <%s> %s", chan, args.nick, line);
+ printf("[%s] <%s> %s", is_local ? chan : "", args.nick, line);
fflush(stdout);
}
return 0;
}
+// Send a message or do a command, possibly to multiple chans
int cmd_msg_chan(irc_session_t *s, char *target, char* line)
{
int i = 0;
@@ -548,8 +569,8 @@ int cmd_msg_chan(irc_session_t *s, char *target, char* line)
cont = 0;
tmp = target[i];
target[i] = 0;
- /* TODO manage errors correctly! */
- rsl = do_cmd_msg(s, one_target, line);
+ // return value is the max of seen return values, ie. some kind of "or"
+ rsl = max(rsl, do_cmd_msg(s, one_target, line));
target[i] = tmp;
one_target = target + i + 1;
}
@@ -559,9 +580,11 @@ int cmd_msg_chan(irc_session_t *s, char *target, char* line)
return rsl;
}
+// Handle a command request which might not specify a destination
int cmd_msg(irc_session_t *s, char* target, char* line)
{
int i = 0;
+ int ret;
char *msg[2*MAX_LEN+2];
/* Manage the fact that target may be "" */
@@ -596,9 +619,9 @@ int cmd_msg(irc_session_t *s, char* target, char* line)
//TODO2: ugly, could have generated the comma-separated string
//like for last_chans_out!
for (i = 0; i < args.n_channels; i++)
- cmd_msg_chan(s, args.channels[i], line);
+ ret = max(ret, cmd_msg_chan(s, args.channels[i], line));
/* TODO return value */
- return 0;
+ return ret;
default:
return 42; // won't happen
@@ -607,42 +630,34 @@ int cmd_msg(irc_session_t *s, char* target, char* line)
return cmd_msg_chan(s, target, line);
}
}
-
-THREAD_FUNCTION(irc_listen)
-{
- irc_session_t * sp = (irc_session_t *) arg;
- // TODO, also do you need '#' or not?
- irc_option_set( sp, LIBIRC_OPTION_SSL_NO_VERIFY );
- irc_run(sp);
- return 0;
-}
-
-void dump_event (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
+
+// Manage an event
+void manage_event (irc_session_t *session, const char *event, const char *origin,
+ const char **params, unsigned int count)
{
int cnt = 0;
int rsl; // TODO use
if (atoi(event) == LIBIRC_RFC_ERR_ERRONEUSNICKNAME)
{
- /* bad nick */
if (args.force_nick)
{
- die(E_BADNAME, "Invalid nick!");
+ die(E_BADNAME, "Invalid nick");
} else {
// TODO does not work
info("Invalid nick, reverting to \"irctk\"");
strncpy(args.nick, "irctk", MAX_NICK_LEN-1);
rsl = irc_cmd_nick (session, "irctk");
}
- } else if (atoi(event) == LIBIRC_RFC_ERR_NICKCOLLISION || atoi(event) == LIBIRC_RFC_ERR_NICKNAMEINUSE) {
- /* bad nick */
+ } else if (atoi(event) == LIBIRC_RFC_ERR_NICKCOLLISION
+ || atoi(event) == LIBIRC_RFC_ERR_NICKNAMEINUSE) {
if (args.force_nick)
{
- die(E_BADNAME, "Nickname already in use!");
+ die(E_BADNAME, "Nickname already in use");
} else {
int len = strlen(args.nick);
if (len >= MAX_NICK_LEN-1) {
- die(E_BADNAME, "No available nickname found.");
+ die(E_BADNAME, "No available nickname found");
} else {
args.nick[len] = '_';
args.nick[len+1] = 0;
@@ -661,7 +676,9 @@ void dump_event (irc_session_t * session, const char * event, const char * origi
debug("Event \"%s\", origin: \"%s\", params: %d", event, origin ? origin : "NULL", cnt);
}
-void event_nick (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
+// Handle a nick event
+void event_nick (irc_session_t *session, const char *event, const char *origin,
+ const char **params, unsigned int count)
{
if (args.event_to == COMMAND)
printf("[] <%s> /nick %s\n", origin, params[0]);
@@ -669,10 +686,12 @@ void event_nick (irc_session_t * session, const char * event, const char * origi
printf("[] -!- %s is now known as %s\n", origin, params[0]);
}
-void event_join (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
+// Handle a join event
+void event_join (irc_session_t * session, const char *event, const char *origin,
+ const char ** params, unsigned int count)
{
// TODO check if it is us!
- dump_event (session, event, origin, params, count);
+ manage_event(session, event, origin, params, count);
irc_cmd_user_mode (session, "+i");
if (args.event_to == COMMAND)
@@ -683,23 +702,31 @@ void event_join (irc_session_t * session, const char * event, const char * origi
debug("Joined!");
}
-void event_part (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
+// Handle a part event
+void event_part (irc_session_t *session, const char *event, const char *origin,
+ const char **params, unsigned int count)
{
if (args.event_to == COMMAND)
printf("[%s] <%s> /part %s\n", params[0], origin, params[1]);
if (args.event_to == MESSAGE)
- printf("[%s] -!- %s has left %s (%s)\n", params[0], origin, params[0], params[1]);
+ printf("[%s] -!- %s has left %s (%s)\n", params[0], origin, params[0],
+ params[1]);
}
-void event_topic (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
+// Handle a topic event
+void event_topic (irc_session_t *session, const char *event, const char *origin,
+ const char **params, unsigned int count)
{
if (args.event_to == COMMAND)
printf("[%s] <%s> /topic %s\n", params[0], origin, params[1]);
if (args.event_to == MESSAGE)
- printf("[%s] -!- %s changed the topic of %s to %s\n", params[0], origin, params[0], params[1]);
+ printf("[%s] -!- %s changed the topic of %s to %s\n", params[0], origin,
+ params[0], params[1]);
}
-void event_quit (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
+// Handle a quit event
+void event_quit (irc_session_t *session, const char *event, const char *origin,
+ const char **params, unsigned int count)
{
if (args.event_to == COMMAND)
printf("[] <%s> /quit %s\n", origin, params[0]);
@@ -707,7 +734,9 @@ void event_quit (irc_session_t * session, const char * event, const char * origi
printf("[] -!- %s has quit (%s)\n", origin, params[1]);
}
-void event_ctcp_action (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
+// Handle an action
+void event_ctcp_action (irc_session_t *session, const char *event,
+ const char *origin, const char **params, unsigned int count)
{
//TODO where is the channel?!
if (args.event_to == COMMAND)
@@ -716,25 +745,30 @@ void event_ctcp_action (irc_session_t * session, const char * event, const char
printf("[%s] *** %s %s\n", params[0], origin, params[1]);
}
-void event_kick (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
+// Handle a kick event
+void event_kick (irc_session_t *session, const char *event, const char *origin,
+ const char **params, unsigned int count)
{
// TODO check for optional params
if (args.event_to == COMMAND)
printf("[%s] <%s> /kick %s %s\n", params[0], origin, params[1], params[2]);
if (args.event_to == MESSAGE)
- printf("[%s] -!- %s was kicked from %s by %s (%s)\n", params[0], params[1], params[0], origin, params[2]);
+ printf("[%s] -!- %s was kicked from %s by %s (%s)\n", params[0], params[1],
+ params[0], origin, params[2]);
}
-
-void event_connect (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
+// Handle a connect event
+void event_connect (irc_session_t *session, const char *event, const char *origin,
+ const char **params, unsigned int count)
{
irc_ctx_t * ctx = (irc_ctx_t *) irc_get_ctx (session);
- dump_event (session, event, origin, params, count);
+ int i;
+
+ manage_event(session, event, origin, params, count);
ctx->ready = 1;
debug("Connected!");
- int i;
for (i = 0; i < ctx->n_channels; i++)
{
debug("Attempt to join %s", ctx->channels[i]);
@@ -742,14 +776,14 @@ void event_connect (irc_session_t * session, const char * event, const char * or
}
}
-
-void event_channel (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
+// Handle a channel event
+void event_channel (irc_session_t *session, const char *event,
+ const char *origin, const char **params, unsigned int count)
{
- int i=0;
- int ok = 1, ok2;
+ int i = 0, ok = 1, ok2;
const char* pruned;
- if ( count != 2 )
- return;
+
+ if (count != 2) return;
if (args.filter)
if (strcmp(params[0], args.nick))
@@ -760,10 +794,8 @@ void event_channel (irc_session_t * session, const char * event, const char * or
/* TODO test if ',' or ':' to avoid prefix nicks */
}
- if (ok)
- {
- if (!args.prune)
- {
+ if (ok) {
+ if (!args.prune) {
printf ("[%s] <", params[0]);
if (!origin)
printf("someone");
@@ -778,10 +810,8 @@ void event_channel (irc_session_t * session, const char * event, const char * or
} else {
pruned = params[1];
ok2 = 1;
- while(pruned[0] != ':')
- {
- if (!pruned[0] || pruned[0] == ' ')
- {
+ while(pruned[0] != ':') {
+ if (!pruned[0] || pruned[0] == ' ') {
ok2 = 0;
break;
}
@@ -797,33 +827,36 @@ void event_channel (irc_session_t * session, const char * event, const char * or
printf("%s\n", pruned);
}
- if (strcmp(params[0], args.nick)) // if addressed in our private chan, reply on the sender's priv chan
+ // if addressed in our private chan, reply on the sender's priv chan
+ if (strcmp(params[0], args.nick))
strncpy(args.last_chan_in, params[0], MAX_LEN-1);
else strncpy(args.last_chan_in, origin?origin:"someone", MAX_LEN-1);
strncpy(args.last_nick_in, origin?origin:"someone", MAX_LEN-1);
fflush(stdout);
}
-
}
-
-void event_privmsg (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
+// Handle a privmsg
+void event_privmsg (irc_session_t *session, const char *event,
+ const char *origin, const char **params, unsigned int count)
{
- dump_event (session, event, origin, params, count);
+ manage_event(session, event, origin, params, count);
/* TODO sure? */
event_channel (session, event, origin, params, count);
}
-
-void event_numeric (irc_session_t * session, unsigned int event, const char * origin, const char ** params, unsigned int count)
+// Handle a numeric event
+void event_numeric (irc_session_t *session, unsigned int event,
+ const char *origin, const char **params, unsigned int count)
{
char buf[24];
sprintf (buf, "%d", event);
- dump_event (session, buf, origin, params, count);
+ manage_event(session, buf, origin, params, count);
}
+
irc_session_t* do_connect()
{
irc_session_t *s;
@@ -835,17 +868,17 @@ irc_session_t* do_connect()
callbacks.event_nick = event_nick;
callbacks.event_quit = event_quit;
callbacks.event_part = event_part;
- callbacks.event_mode = dump_event;
+ callbacks.event_mode = manage_event;
callbacks.event_topic = event_topic;
callbacks.event_kick = event_kick;
callbacks.event_channel = event_channel;
callbacks.event_privmsg = event_privmsg;
- callbacks.event_notice = dump_event;
- callbacks.event_invite = dump_event;
- callbacks.event_umode = dump_event;
- callbacks.event_ctcp_rep = dump_event;
+ callbacks.event_notice = manage_event;
+ callbacks.event_invite = manage_event;
+ callbacks.event_umode = manage_event;
+ callbacks.event_ctcp_rep = manage_event;
callbacks.event_ctcp_action = event_ctcp_action;
- callbacks.event_unknown = dump_event;
+ callbacks.event_unknown = manage_event;
callbacks.event_numeric = event_numeric;
//TODO callbacks.event_dcc_chat_req = irc_event_dcc_chat;
@@ -856,7 +889,6 @@ irc_session_t* do_connect()
if (!s)
die(E_SESSION, "Could not create session");
-
if (!args.with_host)
irc_option_set (s, LIBIRC_OPTION_STRIPNICKS);
irc_set_ctx (s, &args);
@@ -865,17 +897,28 @@ irc_session_t* do_connect()
debug("Connecting to %s port %d with nick %s...",
args.server, args.port, args.nick);
-
- if (irc_connect (s, args.server, args.port, args.password, args.nick, args.username, args.realname))
- die(E_CONNECT, "Could not connect: %s\n", irc_strerror (irc_errno(s)));
+ if (irc_connect(s, args.server, args.port, args.password, args.nick,
+ args.username, args.realname))
+ die(E_CONNECT, "Could not connect: %s", irc_strerror (irc_errno(s)));
return s;
}
+// The IRC thread entry point
+static void* irc_listen (void *arg)
+{
+ irc_session_t * sp = (irc_session_t *) arg;
+ // TODO, also do you need '#' or not?
+ irc_option_set(sp, LIBIRC_OPTION_SSL_NO_VERIFY);
+ irc_run(sp);
+ return 0;
+}
+
+// Start the IRC thread and monitor stdin
int start (int max_wait)
{
irc_session_t * s;
- thread_id_t tid;
+ pthread_t tid;
char *line = NULL;
int res, size=100;
struct timeval tp1, tp2;
@@ -889,8 +932,8 @@ int start (int max_wait)
debug("Starting thread...");
- if (CREATE_THREAD (&tid, irc_listen, s))
- die(E_THREAD, "CREATE_THREAD failed: %s", strerror(errno)); // TODO spurious \n
+ if (pthread_create (&tid, 0, irc_listen, (void*) s) != 0)
+ die(E_THREAD, "Could not create thread: %s", strerror(errno));
debug("Thread started!");
@@ -901,12 +944,10 @@ int start (int max_wait)
gettimeofday(&tp1, NULL);
- if (!args.ready)
- {
+ if (!args.ready) {
waiting = 0;
debug("Waiting for the connection to be ready...");
- while (waiting < max_wait && !args.ready)
- {
+ while (waiting < max_wait && !args.ready) {
debug("waiting (%d)", waiting);
sleep(1);
waiting++;
@@ -923,11 +964,9 @@ int start (int max_wait)
}
}
- while ( (res = getline((char**) &line, (size_t*) &size, stdin)) != -1 )
- {
+ while ((res = getline((char**) &line, (size_t*) &size, stdin)) != -1) {
debug("startloop : got %s, waiting", line);
- if (!args.ready)
- {
+ if (!args.ready) {
info("Connection lost, reconnecting...");
return start(max_wait);
}
@@ -954,7 +993,7 @@ int start (int max_wait)
while (line[i] != ']' && line[i])
i++;
if (!line[i])
- die(E_BADLINE, "Malformed address prefix.");
+ die(E_BADLINE, "Malformed address prefix");
msg = line + i;
if (msg[0] == ' ')
msg++;
@@ -985,13 +1024,17 @@ int start (int max_wait)
int main (int argc, char **argv)
{
+ // initialize the default option values
initialize_args();
+ // parse command line arguments to set option values
argp_parse (&argp, argc, argv, 0, 0, &args);
+ // initialize last_chan_in and last_chan_out
strncpy(args.last_chan_in, first_chan(), MAX_LEN-1);
strncpy(args.last_chans_out, first_chan(), MAX_LEN-1);
+ // start trying to connet with the initial retry interval
return start(args.retry_after);
}