]> Pileus Git - ~andy/lamechat/blob - chat.c
Refactor chat.
[~andy/lamechat] / chat.c
1 /*
2  * Copyright (C) 2017 Andy Spencer <andy753421@gmail.com>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <stdarg.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <time.h>
23
24 #include "util.h"
25 #include "conf.h"
26 #include "chat.h"
27 #include "view.h"
28
29 /* Global data */
30 server_t  *servers;
31 channel_t *channels;
32 message_t *messages;
33 int        history;
34
35 /* Local data */
36 static buf_t srv_buf;
37 static buf_t chan_buf;
38 static buf_t msg_buf;
39
40 static const char *proto_map[] = {
41         [IRC]  "irc",
42         [XMPP] "xmpp",
43 };
44
45 /* View init */
46 void chat_init(void)
47 {
48         servers  = (server_t*)srv_buf.data;
49         channels = (channel_t*)chan_buf.data;
50         messages = (message_t*)msg_buf.data;
51         history  = 0;
52
53         irc_init();
54         xmpp_init();
55 }
56
57 void chat_config(const char *group, const char *name, const char *key, const char *value)
58 {
59         int        protocol = -1;
60         server_t  *server   = NULL;
61         channel_t *channel  = NULL;
62
63         if (match(group, "server")) {
64                 server = find_server(name);
65                 if (match(key, "")) {
66                         get_name(name);
67                 }
68                 else if (match(key, "protocol")) {
69                         protocol = get_enum(value, proto_map, N_ELEMENTS(proto_map));
70                         server = add_server(name, protocol);
71                 }
72                 else if (server) {
73                         protocol = server->protocol;
74                 }
75                 else {
76                         error("No server found for [%s]", name);
77                 }
78         }
79
80         if (match(group, "channel")) {
81                 channel = find_channel(name);
82                 if (match(key, "")) {
83                         get_name(name);
84                 }
85                 else if (match(key, "server")) {
86                         server = find_server(get_string(value));
87                         if (!server)
88                                 error("server '%s' does not exist", name);
89                         channel = add_channel(name, server);
90                         protocol = server->protocol;
91                         server = NULL;
92                 }
93                 else if (channel) {
94                         protocol = channel->server->protocol;
95                 }
96                 else {
97                         error("No channel found for [%s]", name);
98                 }
99         }
100
101         debug("chat_config: [%s-%s \"%s\"] %s = %s",
102                         protocol>=0 ? proto_map[protocol] : "none",
103                         group, name, key, value,
104                         server, channel);
105
106         switch (protocol) {
107                 case IRC:
108                         irc_config(server, channel, group, name, key, value);
109                         break;
110                 case XMPP:
111                         xmpp_config(server, channel, group, name, key, value);
112                         break;
113         }
114 }
115
116 void chat_notice(const char *channel, const char *from, const char *fmt, ...)
117 {
118         static char buf[1024];
119
120         va_list ap;
121         va_start(ap, fmt);
122         vsnprintf(buf, sizeof(buf), fmt, ap);
123         va_end(ap);
124
125         chat_recv(channel, from, buf);
126 }
127
128 void chat_recv(const char *channel, const char *from, const char *text)
129 {
130         append(&msg_buf, NULL, sizeof(message_t));
131         messages = (message_t*)msg_buf.data;
132
133         message_t *msg = &messages[history];
134         msg->channel = find_channel(channel);
135         msg->when = time(NULL);
136         msg->from = strcopy(from);
137         msg->text = strcopy(text);
138
139         history++;
140         view_draw();
141 }
142
143 void chat_send(const char *channel_name, const char *text)
144 {
145         channel_t *channel = find_channel(channel_name);
146
147         append(&msg_buf, NULL, sizeof(message_t));
148         messages = (message_t*)msg_buf.data;
149
150         message_t *msg = &messages[history];
151         msg->channel = channel;
152         msg->when = time(NULL);
153         msg->from = strcopy("andy");
154         msg->text = strcopy(text);
155         history++;
156
157         irc_send(msg);
158         xmpp_send(msg);
159
160         view_draw();
161 }
162
163 void chat_exit(void)
164 {
165         irc_exit();
166         xmpp_exit();
167
168         for (int i = 0; i < history; i++)
169                 free((void*)messages[i].text);
170         release(&msg_buf);
171 }
172
173 /* Server and channel function */
174 server_t *add_server(const char *name, protocol_t protocol)
175 {
176         server_t *server = NULL;
177         debug("adding %s server \"%s\"", proto_map[protocol], name);
178         switch (protocol) {
179                 case IRC:
180                         server = irc_server();
181                         break;
182                 case XMPP:
183                         server = xmpp_server();
184                         break;
185         }
186         server->next = servers;
187         server->name = strcopy(name);
188         server->protocol = protocol;
189         return (servers = server);
190 }
191
192 channel_t *add_channel(const char *name, server_t *server)
193 {
194         channel_t *channel = NULL;
195         debug("adding %s channel \"%s\"", server->name, name);
196         switch (server->protocol) {
197                 case IRC:
198                         channel = irc_channel();
199                         break;
200                 case XMPP:
201                         channel = xmpp_channel();
202                         break;
203         }
204         channel->next = channels;
205         channel->name = strcopy(name);
206         channel->server = server;
207         return (channels = channel);
208 }
209
210 server_t *find_server(const char *name)
211 {
212         for (server_t *cur = servers; cur; cur = cur->next)
213                 if (match(cur->name, name))
214                         return cur;
215         return NULL;
216 }
217
218 channel_t *find_channel(const char *name)
219 {
220         for (channel_t *cur = channels; cur; cur = cur->next) {
221                 if (match(cur->name, name))
222                         return cur;
223         }
224         return NULL;
225 }
226