]> Pileus Git - ~andy/lamechat/blobdiff - chat.c
Make logfile optional.
[~andy/lamechat] / chat.c
diff --git a/chat.c b/chat.c
index e35271a9b6470daea18c1a8ebf912c6b613443eb..b0d008604a221e19e14adae217bc6c87ce858681 100644 (file)
--- a/chat.c
+++ b/chat.c
 #include <string.h>
 #include <time.h>
 
+#include <errno.h>
+#include <wordexp.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
 #include "util.h"
 #include "conf.h"
 #include "chat.h"
 #include "view.h"
 
 /* Global data */
-log_t *chat_log;
-int    chat_len;
+server_t  *servers;
+channel_t *channels;
+user_t    *users;
+message_t *messages;
+int        history;
 
 /* Local data */
-static buf_t log_buf;
+static char *log_dir;
+static buf_t msg_buf;
+
+static const char *proto_map[] = {
+       [IRC]  "irc",
+       [XMPP] "xmpp",
+};
 
 /* Local functions */
+void strdcat(char *dst, const char *src, size_t n)
+{
+       int di = 0, si = 0;
+       while (di < (n-1) && dst[di])
+               di++;
+       while (di < (n-1) && src[si]) {
+               if (src[si] == '/')
+                       dst[di++] = (si++,'_');
+               else
+                       dst[di++] = src[si++];
+       }
+       dst[di] = '\0';
+}
+
+static void init_logs()
+{
+       if (!log_dir)
+               return;
+
+       wordexp_t wexp;
+       wordexp(log_dir, &wexp, WRDE_NOCMD);
+       if (wexp.we_wordc > 1)
+               error("Found multiple log dirs: %s\n  %s\n  %s\n  ...",
+                       log_dir, wexp.we_wordv[0], wexp.we_wordv[1]);
+       strset(&log_dir, wexp.we_wordv[0]);
+       if (mkdir(log_dir, 0755) && (errno != EEXIST))
+               error("Failed to create log dir: %s", log_dir);
+       wordfree(&wexp);
+}
+
+static void write_log(message_t *msg)
+{
+       static char log_path[4096];
 
-/* View init */
+       if (!log_dir)
+               return;
+
+       channel_t *chan = msg->channel;
+       server_t  *srv  = chan->server;
+
+       if (!chan->log) {
+               /* Create server directory */
+               strncpy(log_path, log_dir,    sizeof(log_path));
+               strncat(log_path, "/",        sizeof(log_path));
+               strdcat(log_path, srv->name,  sizeof(log_path));
+               if (!mkdir(log_path, 0755)) {
+                       debug("Failed to create server log dir\n");
+                       return;
+               }
+
+               /* Open log file directory */
+               strncat(log_path, "/",        sizeof(log_path));
+               strdcat(log_path, chan->name, sizeof(log_path));
+               strncat(log_path, ".log",     sizeof(log_path));
+               if (!(chan->log = fopen(log_path, "a+"))) {
+                       debug("Cannot open log file: %s\n", log_path);
+                       return;
+               }
+       }
+
+       time_t timep = msg->when;
+       struct tm *tm = gmtime(&timep);
+
+       fprintf(chan->log, "(%04d-%02d-%02d %02d:%02d:%02d) %s%s %s\n",
+                       tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
+                       tm->tm_hour, tm->tm_min, tm->tm_sec,
+                       msg->from ? msg->from->name : "***",
+                       msg->from ? ":"             : "",
+                       msg->text);
+       fflush(chan->log);
+}
+
+/* Chat init */
 void chat_init(void)
 {
-       chat_log = (log_t*)log_buf.data;
-       chat_len = 0;
+       messages = (message_t*)msg_buf.data;
+       history  = 0;
 
+       init_logs();
        irc_init();
        xmpp_init();
 }
 
+void proto_config(const char *pname, const char *sname, const char *cname,
+                  const char *group, const char *name,
+                  const char *key, const char *value)
+{
+       protocol_t proto = -1;
+       server_t  *srv   = NULL;
+       channel_t *chan  = NULL;
+
+       for (srv = servers; srv; srv = srv->next)
+               if (match(sname, srv->name))
+                       break;
+       for (chan = channels; chan; chan = chan->next)
+               if (match(cname, chan->name))
+                       break;
+
+       if      (pname) proto = get_map(pname, proto_map);
+       else if (srv)   proto = srv->protocol;
+       else if (chan)  proto = chan->server->protocol;
+
+       debug("chat_config: [%s-%s \"%s\"] %s = %s",
+                       proto>=0 ? proto_map[proto] : "none",
+                       group, name, key, value);
+
+       switch (proto) {
+               case IRC:
+                       irc_config(srv, chan, group, name, key, value);
+                       break;
+               case XMPP:
+                       xmpp_config(srv, chan, group, name, key, value);
+                       break;
+       }
+}
+
 void chat_config(const char *group, const char *name, const char *key, const char *value)
 {
-       irc_config(group, name, key, value);
-       xmpp_config(group, name, key, value);
+       if (match(group, "general")) {
+               if (match(key, "logdir"))
+                       log_dir = strcopy(get_string(value));
+       }
+       if (match(group, "server")) {
+               if (match(key, ""))
+                       get_name(name);
+               else if (match(key, "protocol"))
+                       proto_config(value, NULL, NULL, group, name, key, value);
+               else
+                       proto_config(NULL, name, NULL, group, name, key, value);
+       }
+       if (match(group, "channel")) {
+               if (match(key, ""))
+                       get_name(name);
+               else if (match(key, "server"))
+                       proto_config(NULL, value, NULL, group, name, key, value);
+               else
+                       proto_config(NULL, NULL, name, group, name, key, value);
+       }
+       if (match(group, "autojoin")) {
+               if (match(key, ""))
+                       get_name(name);
+               else
+                       proto_config(NULL, name, key, group, name, key, value);
+       }
 }
 
-void chat_notice(const char *channel, const char *from, const char *fmt, ...)
+void chat_recv(channel_t *channel, user_t *from, const char *text)
 {
-       static char buf[1024];
+       append(&msg_buf, NULL, sizeof(message_t));
+       messages = (message_t*)msg_buf.data;
 
-       va_list ap;
-       va_start(ap, fmt);
-       vsnprintf(buf, sizeof(buf), fmt, ap);
-       va_end(ap);
+       message_t *msg = &messages[history];
+       msg->channel = channel;
+       msg->when = time(NULL);
+       msg->from = from;
+       msg->text = strcopy(text);
 
-       chat_recv(channel, from, buf);
+       history++;
+       write_log(msg);
+       view_draw();
 }
 
-void chat_recv(const char *channel, const char *from, const char *msg)
+void chat_complete(channel_t *channel, const char *text)
 {
-       append(&log_buf, NULL, sizeof(log_t));
-       chat_log = (log_t*)log_buf.data;
-
-       log_t *log = &chat_log[chat_len];
-       log->when = time(NULL);
-       log->from = strcopy(from);
-       log->channel = strcopy(channel);
-       log->msg  = strcopy(msg);
+       switch (channel->server->protocol) {
+               case IRC:
+                       irc_complete(channel, text);
+                       break;
+               case XMPP:
+                       xmpp_complete(channel, text);
+                       break;
+       }
+}
 
-       chat_len++;
-       view_draw();
+void chat_send(channel_t *channel, const char *text)
+{
+       switch (channel->server->protocol) {
+               case IRC:
+                       irc_send(channel, text);
+                       break;
+               case XMPP:
+                       xmpp_send(channel, text);
+                       break;
+       }
 }
 
-void chat_send(const char *channel, const char *msg)
+void chat_update(void)
 {
-       append(&log_buf, NULL, sizeof(log_t));
-       chat_log = (log_t*)log_buf.data;
-
-       log_t *log = &chat_log[chat_len];
-       log->when = time(NULL);
-       log->from = "andy";
-       log->channel = strcopy(channel);
-       log->msg  = strcopy(msg);
-
-       chat_len++;
-       irc_send(channel, msg);
-       xmpp_send(channel, msg);
        view_draw();
 }
 
@@ -100,7 +244,36 @@ void chat_exit(void)
        irc_exit();
        xmpp_exit();
 
-       for (int i = 0; i < chat_len; i++)
-               free((void*)chat_log[i].msg);
-       release(&log_buf);
+       for (int i = 0; i < history; i++)
+               free((void*)messages[i].text);
+       release(&msg_buf);
+}
+
+/* Server and channel function */
+void add_server(server_t *server)
+{
+       protocol_t proto = server->protocol;
+       debug("adding %s server \"%s\"", proto_map[proto], server->name);
+       server_t **last = &servers;
+       while (*last)
+               last = &(*last)->next;
+       *last = server;
+}
+
+void add_channel(channel_t *channel)
+{
+       debug("adding %s channel \"%s\"", channel->server->name, channel->name);
+       channel_t **last = &channels;
+       while (*last)
+               last = &(*last)->next;
+       *last = channel;
+}
+
+void add_user(user_t *user)
+{
+       debug("adding %s user \"%s\"", user->server->name, user->name);
+       user_t **last = &users;
+       while (*last)
+               last = &(*last)->next;
+       *last = user;
 }