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