More removal of $Id$ tags
[citadel.git] / citadel / utillib / citadel_ipc.c
index 0428937ad1ad469e5480e898fac6f3e9c005cc5e..69a73116f376f683c1f0b787c3442a39c853a691 100644 (file)
@@ -1,5 +1,4 @@
-/* $Id$ 
- *
+/*
  * Copyright (c) 1987-2009 by the citadel.org team
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -756,6 +755,8 @@ int CtdlIPCServerInfo(CtdlIPC *ipc, char *cret)
                                        break;
                        case 22:        strcpy(ipc->ServInfo.svn_revision, buf);
                                        break;
+                       case 24:        ipc->ServInfo.guest_logins = atoi(buf);
+                                       break;
                        }
                }
 
@@ -786,7 +787,7 @@ int CtdlIPCReadDirectory(CtdlIPC *ipc, char **listing, char *cret)
 int CtdlIPCSetLastRead(CtdlIPC *ipc, long msgnum, char *cret)
 {
        register int ret;
-       char aaa[16];
+       char aaa[64];
 
        if (!cret) return -2;
 
@@ -964,7 +965,7 @@ int CtdlIPCRoomInfo(CtdlIPC *ipc, char **iret, char *cret)
 /* DELE */
 int CtdlIPCDeleteMessage(CtdlIPC *ipc, long msgnum, char *cret)
 {
-       char aaa[16];
+       char aaa[64];
 
        if (!cret) return -2;
        if (!msgnum) return -2;
@@ -997,7 +998,7 @@ int CtdlIPCMoveMessage(CtdlIPC *ipc, int copy, long msgnum, const char *destroom
 /* KILL */
 int CtdlIPCDeleteRoom(CtdlIPC *ipc, int for_real, char *cret)
 {
-       char aaa[16];
+       char aaa[64];
 
        if (!cret) return -2;
 
@@ -1108,7 +1109,7 @@ int CtdlIPCValidateUser(CtdlIPC *ipc, const char *username, int axlevel, char *c
 
        if (!cret) return -2;
        if (!username) return -2;
-       if (axlevel < 0 || axlevel > 7) return -2;
+       if (axlevel < AxDeleted || axlevel > AxAideU) return -2;
 
        aaa = (char *)malloc(strlen(username) + 17);
        if (!aaa) return -1;
@@ -1123,7 +1124,7 @@ int CtdlIPCValidateUser(CtdlIPC *ipc, const char *username, int axlevel, char *c
 /* EINF */
 int CtdlIPCSetRoomInfo(CtdlIPC *ipc, int for_real, const char *info, char *cret)
 {
-       char aaa[16];
+       char aaa[64];
 
        if (!cret) return -1;
        if (!info) return -1;
@@ -1610,7 +1611,7 @@ int CtdlIPCGetInstantMessage(CtdlIPC *ipc, char **listing, char *cret)
 /* mode is 0 = enable, 1 = disable, 2 = status */
 int CtdlIPCEnableInstantMessageReceipt(CtdlIPC *ipc, int mode, char *cret)
 {
-       char aaa[16];
+       char aaa[64];
 
        if (!cret) return -2;
 
@@ -1668,7 +1669,7 @@ int CtdlIPCListUsersWithBios(CtdlIPC *ipc, char **listing, char *cret)
 /* STEL */
 int CtdlIPCStealthMode(CtdlIPC *ipc, int mode, char *cret)
 {
-       char aaa[16];
+       char aaa[64];
 
        if (!cret) return -1;
 
@@ -1680,7 +1681,7 @@ int CtdlIPCStealthMode(CtdlIPC *ipc, int mode, char *cret)
 /* TERM */
 int CtdlIPCTerminateSession(CtdlIPC *ipc, int sid, char *cret)
 {
-       char aaa[16];
+       char aaa[64];
 
        if (!cret) return -1;
 
@@ -1860,10 +1861,15 @@ int CtdlIPCAideSetUserParameters(CtdlIPC *ipc, const struct ctdluser *uret, char
 /* GPEX */
 /* which is 0 = room, 1 = floor, 2 = site, 3 = default for mailboxes */
 /* caller must free the struct ExpirePolicy */
-int CtdlIPCGetMessageExpirationPolicy(CtdlIPC *ipc, int which,
+int CtdlIPCGetMessageExpirationPolicy(CtdlIPC *ipc, GPEXWhichPolicy which,
                struct ExpirePolicy **policy, char *cret)
 {
-       static char *proto[] = {"room", "floor", "site", "mailboxes" };
+       static char *proto[] = {
+               strof(roompolicy),
+               strof(floorpolicy),
+               strof(sitepolicy),
+               strof(mailboxespolicy)
+       };
        char cmd[256];
        register int ret;
 
@@ -2001,7 +2007,7 @@ int CtdlIPCSetRoomNetworkConfig(CtdlIPC *ipc, const char *listing, char *cret)
 /* REQT */
 int CtdlIPCRequestClientLogout(CtdlIPC *ipc, int session, char *cret)
 {
-       char aaa[16];
+       char aaa[64];
 
        if (!cret) return -2;
        if (session < 0) return -2;
@@ -2090,7 +2096,7 @@ int CtdlIPCStartEncryption(CtdlIPC *ipc, char *cret)
        }
        ipc->ssl = temp_ssl;
 
-       BIO_set_close(ipc->ssl->rbio, BIO_NOCLOSE);
+       if (BIO_set_close(ipc->ssl->rbio, BIO_NOCLOSE))
        {
                int bits, alg_bits;
 
@@ -2179,28 +2185,10 @@ int CtdlIPCMessageBaseCheck(CtdlIPC *ipc, char **mret, char *cret)
 
 
 /* ************************************************************************** */
-/*             Stuff below this line is not for public consumption            */
+/*          Stuff below this line is not for public consumption            */
 /* ************************************************************************** */
 
 
-INLINE void CtdlIPC_lock(CtdlIPC *ipc)
-{
-       if (ipc->network_status_cb) ipc->network_status_cb(1);
-#ifdef THREADED_CLIENT
-       pthread_mutex_lock(&(ipc->mutex));
-#endif
-}
-
-
-INLINE void CtdlIPC_unlock(CtdlIPC *ipc)
-{
-#ifdef THREADED_CLIENT
-       pthread_mutex_unlock(&(ipc->mutex));
-#endif
-       if (ipc->network_status_cb) ipc->network_status_cb(0);
-}
-
-
 /* Read a listing from the server up to 000.  Append to dest if it exists */
 char *CtdlIPCReadListing(CtdlIPC *ipc, char *dest)
 {
@@ -2626,55 +2614,79 @@ int CtdlIPCGenericCommand(CtdlIPC *ipc,
 }
 
 
-static int connectsock(char *host, char *service, char *protocol, int defaultPort)
+/*
+ * Connect to a Citadel on a remote host using a TCP/IP socket
+ */
+static int tcp_connectsock(char *host, char *service)
 {
-       struct hostent *phe;
-       struct servent *pse;
-       struct protoent *ppe;
-       struct sockaddr_in sin;
-       int s, type;
-
-       memset(&sin, 0, sizeof(sin));
-       sin.sin_family = AF_INET;
+       struct in6_addr serveraddr;
+       struct addrinfo hints;
+       struct addrinfo *res = NULL;
+       struct addrinfo *ai = NULL;
+       int rc = (-1);
+       int sock = (-1);
 
-       pse = getservbyname(service, protocol);
-       if (pse != NULL) {
-               sin.sin_port = pse->s_port;
-       }
-       else if (atoi(service) > 0) {
-               sin.sin_port = htons(atoi(service));
-       }
-       else {
-               sin.sin_port = htons(defaultPort);
+       if ((host == NULL) || IsEmptyStr(host)) {
+               service = DEFAULT_HOST ;
        }
-       phe = gethostbyname(host);
-       if (phe) {
-               memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
-       } else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
-               return -1;
+       if ((service == NULL) || IsEmptyStr(service)) {
+               service = DEFAULT_PORT ;
        }
-       if ((ppe = getprotobyname(protocol)) == 0) {
-               return -1;
+
+       memset(&hints, 0x00, sizeof(hints));
+       hints.ai_flags = AI_NUMERICSERV;
+       hints.ai_family = AF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+
+       /*
+        * Handle numeric IPv4 and IPv6 addresses
+        */
+       rc = inet_pton(AF_INET, host, &serveraddr);
+       if (rc == 1) {                                          /* dotted quad */
+               hints.ai_family = AF_INET;
+               hints.ai_flags |= AI_NUMERICHOST;
        }
-       if (!strcmp(protocol, "udp")) {
-               type = SOCK_DGRAM;
-       } else {
-               type = SOCK_STREAM;
+       else {
+               rc = inet_pton(AF_INET6, host, &serveraddr);
+               if (rc == 1) {                                  /* IPv6 address */
+                       hints.ai_family = AF_INET6;
+                       hints.ai_flags |= AI_NUMERICHOST;
+               }
        }
 
-       s = socket(PF_INET, type, ppe->p_proto);
-       if (s < 0) {
-               return -1;
+       /* Begin the connection process */
+
+       rc = getaddrinfo(host, service, &hints, &res);
+       if (rc != 0) {
+               return(-1);
        }
 
-       if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
-               close(s);
-               return -1;
+       /*
+        * Try all available addresses until we connect to one or until we run out.
+        */
+       for (ai = res; ai != NULL; ai = ai->ai_next) {
+               sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+               if (sock < 0) return(-1);
+
+               rc = connect(sock, ai->ai_addr, ai->ai_addrlen);
+               if (rc >= 0) {
+                       return(sock);           /* Connected! */
+               }
+               else {
+                       close(sock);            /* Failed.  Close the socket to avoid fd leak! */
+               }
        }
 
-       return (s);
+       return(-1);
 }
 
+
+
+
+
+/*
+ * Connect to a Citadel on the local host using a unix domain socket
+ */
 static int uds_connectsock(int *isLocal, char *sockpath)
 {
        struct sockaddr_un addr;
@@ -3252,14 +3264,36 @@ CtdlIPC* CtdlIPC_new(int argc, char **argv, char *hostbuf, char *portbuf)
                }
                if (hostbuf != NULL) strcpy(hostbuf, cithost);
                if (portbuf != NULL) strcpy(portbuf, sockpath);
+               strcpy(ipc->ip_hostname, "");
+               strcpy(ipc->ip_address, "");
                return ipc;
        }
 
-       ipc->sock = connectsock(cithost, citport, "tcp", 504);
+       ipc->sock = tcp_connectsock(cithost, citport);
        if (ipc->sock == -1) {
                ifree(ipc);
                return 0;
        }
+
+
+       /* Learn the actual network identity of the host to which we are connected */
+
+       struct sockaddr_in6 clientaddr;
+       unsigned int addrlen = sizeof(clientaddr);
+
+       ipc->ip_hostname[0] = 0;
+       ipc->ip_address[0] = 0;
+
+       getpeername(ipc->sock, (struct sockaddr *)&clientaddr, &addrlen);
+       getnameinfo((struct sockaddr *)&clientaddr, addrlen,
+               ipc->ip_hostname, sizeof ipc->ip_hostname, NULL, 0, 0
+       );
+       getnameinfo((struct sockaddr *)&clientaddr, addrlen,
+               ipc->ip_address, sizeof ipc->ip_address, NULL, 0, NI_NUMERICHOST
+       );
+
+       /* stuff other things elsewhere */
+
        if (hostbuf != NULL) strcpy(hostbuf, cithost);
        if (portbuf != NULL) strcpy(portbuf, citport);
        return ipc;