Created
April 25, 2012 02:07
-
-
Save aji/2485532 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* libmowgli: A collection of useful routines for programming. | |
* linetest.c: Testing of the linebuffer | |
* | |
* Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org> | |
* Copyright (c) 2012 Elizabeth J. Myers <elizabeth@sporksmoo.net> | |
* | |
* Permission to use, copy, modify, and/or distribute this software for any | |
* purpose with or without fee is hereby granted, provided that the above | |
* copyright notice and this permission notice appear in all copies. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
* POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
/* CFLAGS = $(pkg-config --cflags libmowgli-2 libunicorn) */ | |
/* LIBS = $(pkg-config --libs libmowgli-2 libunicorn) */ | |
#include <mowgli.h> | |
#include <unicorn.h> | |
#include <stdlib.h> | |
mowgli_eventloop_t *base_eventloop; | |
char buf[512]; | |
typedef struct { | |
mowgli_linebuf_t *linebuf; | |
irc_hook_table_t *events; | |
irc_hook_table_t *commands; | |
irc_message_t *msg; | |
bool prefix; | |
const char *rpl_dest; | |
const char *rpl_command; | |
const char *rpl_issuer; | |
} client_t; | |
void eat_line(mowgli_linebuf_t *linebuf, char *line, size_t len, void *userdata); | |
void write_line(mowgli_linebuf_t *linebuf, char *buf, size_t len) | |
{ | |
printf("> %s\n", buf); | |
mowgli_linebuf_write(linebuf, buf, len); | |
} | |
void client_raw(client_t *client, char *line) | |
{ | |
write_line(client->linebuf, line, strlen(line)); | |
} | |
void client_rawf(client_t *client, const char *fmt, ...) | |
{ | |
char buf[512]; | |
va_list va; | |
va_start(va, fmt); | |
vsprintf(buf, fmt, va); | |
va_end(va); | |
client_raw(client, buf); | |
} | |
void client_replyf(client_t *client, bool prefix, const char *fmt, ...) | |
{ | |
const char *p, *q; | |
char buf[512]; | |
va_list va; | |
p = q = ""; | |
if (prefix && client->prefix) { | |
p = client->rpl_issuer; | |
q = ": "; | |
} | |
va_start(va, fmt); | |
vsprintf(buf, fmt, va); | |
va_end(va); | |
client_rawf(client, "%s %s :%s%s%s", client->rpl_command, client->rpl_dest, p, q, buf); | |
} | |
void cmd_echo(int parc, const char *parv[], void *priv) | |
{ | |
client_t *client = priv; | |
if (parc == 0) { | |
client_replyf(client, true, "Usage: !echo <text>"); | |
return; | |
} | |
client_replyf(client, true, "%s", parv[0]); | |
} | |
void cmd_flip(int parc, const char *parv[], void *priv) | |
{ | |
client_t *client = priv; | |
if (rand() % 2 == 0) { | |
client_replyf(client, false, "heads"); | |
} else { | |
client_replyf(client, false, "tails"); | |
} | |
} | |
void cmd_roll(int parc, const char *parv[], void *priv) | |
{ | |
client_t *client = priv; | |
int sides; | |
if (parc == 0) { | |
client_replyf(client, true, "Usage: !roll <sides>"); | |
return; | |
} | |
sides = atoi(parv[0]); | |
if (sides < 2) { | |
client_replyf(client, true, "Must roll above 2 sides"); | |
return; | |
} | |
client_replyf(client, false, "rolled %d", (rand() % sides) + 1); | |
} | |
void cmd_join(int parc, const char *parv[], void *priv) | |
{ | |
client_t *client = priv; | |
if (strcmp(client->rpl_issuer, "aji")) | |
return; | |
client_rawf(client, "JOIN %s", parv[0]); | |
} | |
void cmd_part(int parc, const char *parv[], void *priv) | |
{ | |
client_t *client = priv; | |
if (strcmp(client->rpl_issuer, "aji")) | |
return; | |
client_rawf(client, "PART %s :byebye", parv[0]); | |
} | |
void dispatch_commands(int parc, const char *parv[], void *priv) | |
{ | |
client_t *client = priv; | |
char *command, *arg; | |
char buf[512]; | |
if (parc != 3) | |
return; | |
client->prefix = true; | |
client->rpl_dest = parv[1]; | |
client->rpl_command = "PRIVMSG"; | |
client->rpl_issuer = parv[0]; | |
if (parv[1][0] != '#') { | |
client->prefix = false; | |
client->rpl_dest = client->rpl_issuer; | |
client->rpl_command = "NOTICE"; | |
} else if (parv[2][0] != '!') { | |
return; | |
} | |
strcpy(buf, parv[2]); | |
command = buf; | |
if (command[0] == '!') | |
command++; | |
arg = strchr(buf, ' '); | |
if (arg != NULL) { | |
*arg++ = '\0'; | |
irc_hook_call(client->commands, command, 1, (const char**)&arg); | |
} else { | |
irc_hook_call(client->commands, command, 0, (const char**)NULL); | |
} | |
} | |
void event_001(int parc, const char *parv[], void *priv) | |
{ | |
client_t *client = priv; | |
} | |
void event_ping(int parc, const char *parv[], void *priv) | |
{ | |
client_t *client = priv; | |
client_rawf(client, "PONG :%s", parv[parc - 1]); | |
} | |
client_t * create_client(const char *server, const char *port, const char *nick, const char *user, const char *realname) | |
{ | |
client_t *client; | |
struct addrinfo hints, *res; | |
bool use_ssl = false; | |
mowgli_vio_sockaddr_t addr; | |
int ret; | |
mowgli_linebuf_t *linebuf; | |
if (*port == '+') | |
{ | |
port++; | |
use_ssl = true; | |
} | |
client = mowgli_alloc(sizeof(client_t)); | |
linebuf = mowgli_linebuf_create(eat_line, client); | |
client->linebuf = linebuf; | |
/* allocate libunicorn structures */ | |
client->events = irc_hook_table_create(); | |
client->commands = irc_hook_table_create(); | |
client->msg = irc_message_create(); | |
/* add events and commands */ | |
irc_hook_add(client->events, "PRIVMSG", dispatch_commands, client); | |
irc_hook_add(client->events, "001", event_001, client); | |
irc_hook_add(client->events, "PING", event_ping, client); | |
irc_hook_add(client->commands, "echo", cmd_echo, client); | |
irc_hook_add(client->commands, "flip", cmd_flip, client); | |
irc_hook_add(client->commands, "roll", cmd_roll, client); | |
irc_hook_add(client->commands, "join", cmd_join, client); | |
irc_hook_add(client->commands, "part", cmd_part, client); | |
/* Do name res */ | |
memset(&hints, 0, sizeof hints); | |
hints.ai_family = AF_UNSPEC; | |
hints.ai_socktype = SOCK_STREAM; | |
if ((ret = getaddrinfo(server, port, &hints, &res)) != 0) | |
{ | |
linebuf->vio->error.op = MOWGLI_VIO_ERR_OP_OTHER; | |
linebuf->vio->error.type = MOWGLI_VIO_ERR_ERRCODE; | |
linebuf->vio->error.code = ret; | |
mowgli_strlcpy(linebuf->vio->error.string, gai_strerror(ret), sizeof(linebuf->vio->error.string)); | |
mowgli_vio_error(linebuf->vio); | |
return NULL; | |
} | |
/* Wrap the VIO object */ | |
if (use_ssl) | |
{ | |
if (mowgli_vio_openssl_setssl(linebuf->vio, NULL) != 0) | |
return NULL; | |
} | |
/* We have to have a socket before starting the linebuf */ | |
if (mowgli_vio_socket(linebuf->vio, res->ai_family, res->ai_socktype, res->ai_protocol) != 0) | |
return NULL; | |
/* Attach the linebuf */ | |
mowgli_linebuf_attach_to_eventloop(linebuf, base_eventloop); | |
/* Do the connect */ | |
if (mowgli_vio_connect(linebuf->vio, mowgli_vio_sockaddr_from_struct(&addr, res->ai_addr, res->ai_addrlen)) != 0) | |
return NULL; | |
/* Write IRC handshake */ | |
snprintf(buf, 512, "USER %s * 8 :%s", user, realname); | |
write_line(client->linebuf, buf, strlen(buf)); | |
snprintf(buf, 512, "NICK %s", nick); | |
write_line(client->linebuf, buf, strlen(buf)); | |
return client; | |
} | |
void eat_line(mowgli_linebuf_t *linebuf, char *line, size_t len, void *userdata) | |
{ | |
char str[512]; | |
client_t *client = userdata; | |
/* Avoid malicious lines -- servers shouldn't send them */ | |
if (linebuf->flags & MOWGLI_LINEBUF_LINE_HASNULLCHAR) | |
return; | |
strncpy(str, line, sizeof(str)); | |
str[len + 1] = '\0'; | |
printf("-> %s\n", str); | |
irc_message_reset(client->msg); | |
irc_message_parse(client->msg, str); | |
/* dispatch */ | |
irc_hook_simple_dispatch(client->events, client->msg); | |
return; | |
} | |
int main(int argc, const char *argv[]) | |
{ | |
client_t *client; | |
const char *serv, *port; | |
if (argc < 3) | |
{ | |
fprintf(stderr, "Not enough arguments\n"); | |
fprintf(stderr, "Usage: %s [server] [(+)port]\n", argv[0]); | |
fprintf(stderr, "For SSL, put a + in front of port\n"); | |
return EXIT_FAILURE; | |
} | |
base_eventloop = mowgli_eventloop_create(); | |
serv = argv[1]; | |
port = argv[2]; | |
client = create_client(serv, port, "libunicorn", "horned", "The libunicorn example bot that does nothing useful"); | |
if (client == NULL) | |
return EXIT_FAILURE; | |
mowgli_eventloop_run(base_eventloop); | |
mowgli_free(client); | |
mowgli_eventloop_destroy(base_eventloop); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment