1 /*
2 * libmowgli: A collection of useful routines for programming.
3 * linetest.c: Testing of the linebuffer
4 *
5 * Copyright (c) 2011 William Pitcock <nenolod@dereferenced.org>
6 * Copyright (c) 2012 Elizabeth J. Myers <elizabeth@sporksmoo.net>
7 *
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
13 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
16 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
18 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
20 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
21 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22 * POSSIBILITY OF SUCH DAMAGE.
23 */
24
25 #include <mowgli.h>
26
27 mowgli_eventloop_t *base_eventloop;
28 char buf[512];
29
30 typedef struct
31 {
32 mowgli_linebuf_t *linebuf;
33 } client_t;
34
35 void eat_line(mowgli_linebuf_t *linebuf, char *line, size_t len, void *userdata);
36
37 void
write_line(mowgli_linebuf_t * linebuf,char * buf,size_t len)38 write_line(mowgli_linebuf_t *linebuf, char *buf, size_t len)
39 {
40 printf("-> %s\n", buf);
41 mowgli_linebuf_write(linebuf, buf, len);
42 }
43
44 client_t *
create_client(const char * server,const char * port,const char * nick,const char * user,const char * realname)45 create_client(const char *server, const char *port, const char *nick, const char *user, const char *realname)
46 {
47 client_t *client;
48 struct addrinfo hints, *res;
49
50 bool use_ssl = false;
51 mowgli_vio_sockaddr_t addr;
52 int ret;
53
54 mowgli_linebuf_t *linebuf;
55
56 if (*port == '+')
57 {
58 port++;
59 use_ssl = true;
60 }
61
62 client = mowgli_alloc(sizeof(client_t));
63
64 linebuf = mowgli_linebuf_create(eat_line, client);
65 client->linebuf = linebuf;
66
67 /* Do name res */
68 memset(&hints, 0, sizeof hints);
69 hints.ai_family = AF_UNSPEC;
70 hints.ai_socktype = SOCK_STREAM;
71
72 if ((ret = getaddrinfo(server, port, &hints, &res)) != 0)
73 {
74 linebuf->vio->error.op = MOWGLI_VIO_ERR_OP_OTHER;
75 linebuf->vio->error.type = MOWGLI_VIO_ERR_ERRCODE;
76 linebuf->vio->error.code = ret;
77 mowgli_strlcpy(linebuf->vio->error.string, gai_strerror(ret), sizeof(linebuf->vio->error.string));
78 mowgli_vio_error(linebuf->vio);
79 return NULL;
80 }
81
82 /* Wrap the VIO object */
83 if (use_ssl)
84 if (mowgli_vio_openssl_setssl(linebuf->vio, NULL, NULL) != 0)
85 return NULL;
86
87 /* We have to have a socket before starting the linebuf */
88
89 if (mowgli_vio_socket(linebuf->vio, res->ai_family, res->ai_socktype, res->ai_protocol) != 0)
90 return NULL;
91
92 /* Attach the linebuf */
93 mowgli_linebuf_attach_to_eventloop(linebuf, base_eventloop);
94
95 /* Do the connect */
96 if (mowgli_vio_connect(linebuf->vio, mowgli_vio_sockaddr_from_struct(&addr, res->ai_addr, res->ai_addrlen)) != 0)
97 return NULL;
98
99 /* Write IRC handshake */
100 snprintf(buf, 512, "USER %s * 8 :%s", user, realname);
101 write_line(client->linebuf, buf, strlen(buf));
102
103 snprintf(buf, 512, "NICK %s", nick);
104 write_line(client->linebuf, buf, strlen(buf));
105
106 return client;
107 }
108
109 void
eat_line(mowgli_linebuf_t * linebuf,char * line,size_t len,void * userdata)110 eat_line(mowgli_linebuf_t *linebuf, char *line, size_t len, void *userdata)
111 {
112 char str[512];
113
114 /* Avoid malicious lines -- servers shouldn't send them */
115 if (linebuf->flags & MOWGLI_LINEBUF_LINE_HASNULLCHAR)
116 return;
117
118 strncpy(str, line, sizeof(str));
119 str[len + 1] = '\0';
120
121 printf("<- %s\n", str);
122
123 /* Since this is just a basic example, we don't have a real dispatcher :p */
124 if (strstr(str, "PING"))
125 {
126 char *pos = strpbrk(str, ":");
127
128 if (pos)
129 {
130 char buf[512];
131 snprintf(buf, 512, "PONG %s", pos);
132 mowgli_linebuf_write(linebuf, buf, strlen(buf));
133 }
134 }
135
136 return;
137 }
138
139 int
main(int argc,const char * argv[])140 main(int argc, const char *argv[])
141 {
142 client_t *client;
143 const char *serv, *port;
144
145 if (argc < 3)
146 {
147 fprintf(stderr, "Not enough arguments\n");
148 fprintf(stderr, "Usage: %s [server] [(+)port]\n", argv[0]);
149 fprintf(stderr, "For SSL, put a + in front of port\n");
150 return EXIT_FAILURE;
151 }
152
153 base_eventloop = mowgli_eventloop_create();
154
155 serv = argv[1];
156 port = argv[2];
157
158 client = create_client(serv, port, "Mowglibot", "Mowglibot", "The libmowgli example bot that does nothing useful");
159
160 if (client == NULL)
161 return EXIT_FAILURE;
162
163 mowgli_eventloop_run(base_eventloop);
164
165 mowgli_free(client);
166 mowgli_eventloop_destroy(base_eventloop);
167
168 return EXIT_SUCCESS;
169 }
170