Add the friend cache.
[cascardo/f2fchat.git] / friend.c
diff --git a/friend.c b/friend.c
new file mode 100644 (file)
index 0000000..58e7bc5
--- /dev/null
+++ b/friend.c
@@ -0,0 +1,162 @@
+/*
+ *  Copyright (C) 2013  Thadeu Lima de Souza Cascardo <cascardo@cascardo.info>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "friend.h"
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+static int connect_friend(struct sockaddr *saddr, char *address, char *port, int *c)
+{
+       struct addrinfo *addresses;
+       struct addrinfo *addr;
+       struct addrinfo hint;
+       int r;
+       int fd = *c = -1;
+       int i;
+       memset(&hint, 0, sizeof(hint));
+       hint.ai_family = AF_UNSPEC;
+       hint.ai_socktype = SOCK_STREAM;
+       hint.ai_protocol = IPPROTO_TCP;
+       hint.ai_flags = AI_ADDRCONFIG;
+       r = getaddrinfo(address, port, &hint, &addresses);
+       if (r) {
+               return r;
+       }
+       for (addr = addresses; addr != NULL; addr = addr->ai_next) {
+               fd = socket(addr->ai_family, addr->ai_socktype,
+                               addr->ai_protocol);
+               if (fd >= 0)
+                       break;
+               close(fd);
+               fd = -1;
+       }
+       freeaddrinfo(addresses);
+       *c = fd;
+       if (fd == -1)
+               return EAI_SYSTEM;
+       return 0;
+}
+
+struct friend {
+       char *name;
+       char *address;
+       char *port;
+       struct sockaddr *saddr;
+};
+
+struct cache {
+       int nfriends;
+       struct friend *friends;
+};
+
+int create_cache(struct cache **cache)
+{
+       *cache = malloc(sizeof(*cache));
+       if (!*cache)
+               return -errno;
+       (*cache)->nfriends = 0;
+       (*cache)->friends = NULL;
+       return 0;
+}
+
+int destroy_cache(struct cache *cache)
+{
+       if (cache->friends)
+               free(cache->friends);
+       free(cache);
+}
+
+int cache_add_friend(struct cache *cache, char *friend, char *address, char *port)
+{
+       struct friend *tfriend;
+       if (!cache->friends) {
+               cache->friends = malloc(sizeof(struct friend));
+               cache->nfriends = 1;
+       } else {
+               struct friend *new_friends;
+               cache->nfriends++;
+               new_friends = realloc(cache->friends, cache->nfriends * sizeof(struct friend));
+               if (!new_friends) {
+                       cache->nfriends--;
+                       return -errno;
+               }
+               cache->friends = new_friends;
+       }
+       tfriend = &cache->friends[cache->nfriends - 1];
+       tfriend->name = friend;
+       tfriend->address = address;
+       tfriend->port = port;
+       tfriend->saddr = NULL;
+       return 0;
+}
+
+int load_cache(struct cache *cache, char *fname)
+{
+       FILE *file;
+       int err = 0;
+       char *buffer = NULL;
+       size_t len = 0;
+       int r;
+       file = fopen(fname, "r");
+       if (!file)
+               return -errno;
+       while ((r = getline(&buffer, &len, file)) > 0) {
+               char *name;
+               char *address;
+               char *port;
+               char *end;
+               name = buffer;
+               address = name;
+               while (*++address != '\t');
+               *address++ = '\0';
+               port = address;
+               while (*++port != '\t');
+               *port++ = '\0';
+               end = port;
+               while (*++end != '\n');
+               *end = '\0';
+               fprintf(file, "%s\t%s\t%s\n", name, address, port);
+               cache_add_friend(cache, strdup(name), strdup(address), strdup(port));
+       }
+out:
+       fclose(file);
+       return err;
+}
+
+int store_cache(struct cache *cache, char *fname)
+{
+       FILE *file;
+       int err = 0;
+       int i;
+       file = fopen(fname, "w");
+       if (!file)
+               return -errno;
+       for (i = 0; i < cache->nfriends; i++) {
+               struct friend *friend = &cache->friends[i];
+               fprintf(file, "%s\t%s\t%s\n", friend->name, friend->address, friend->port);
+       }
+out:
+       fclose(file);
+       return err;
+}