]> code.citadel.org Git - citadel.git/blobdiff - citadel/serv_icq.c
* Removed all of the thread cancellation cruft that is no longer necessary
[citadel.git] / citadel / serv_icq.c
index 1d176feef167b4deeba8532bb69acf4fe573a5fd..30f3dff55809243dfabc47f8173d36cda19820f8 100644 (file)
@@ -1,7 +1,7 @@
 /* 
  * serv_icq.c
  *
- * This is a modified version of Denis' ICQLIB, a very cleanly
+ * This is a modified version of Denis V. Dmitrienko's ICQLIB, a very cleanly
  * written implementation of the Mirabilis ICQ client protocol.  The library
  * has been modified rather than merely utilized because we need it to be
  * threadsafe in order to tie it into the Citadel server.
@@ -24,6 +24,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include <time.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <limits.h>
 #include "sysdep.h"
-#ifdef HAVE_PTHREAD_H
-#include <pthread.h>
-#endif
 #include "citadel.h"
 #include "server.h"
 #include "dynloader.h"
 #include "tools.h"
 #include "citserver.h"
+#include "locate_host.h"
 #include "msgbase.h"
+#include "sysdep_decls.h"
+#include "support.h"
+#include "room_ops.h"
+#include "user_ops.h"
 
 /*
  * Contact list in memory
@@ -49,44 +52,12 @@ struct CtdlICQ_CL {
        DWORD uin;
        char name[32];
        DWORD status;
+       char host[26];
 };
 
 
-struct ctdl_icq_handle {
-       int icq_Sok;
-       BOOL icq_Russian;
-       BYTE icq_ServMess[8192];
-       WORD icq_SeqNum;
-       DWORD icq_OurIp;
-       DWORD icq_OurPort;
-       DWORD icq_Uin;
-       icq_ContactItem *icq_ContFirst;
-       DWORD icq_Status;
-       char *icq_Password;
-       BYTE icq_LogLevel;
-       BYTE icq_UseProxy;
-       char *icq_ProxyHost;
-       WORD icq_ProxyPort;
-       int icq_ProxyAuth;
-       char *icq_ProxyName;
-       char *icq_ProxyPass;
-       int icq_ProxySok;
-       DWORD icq_ProxyDestHost;
-       WORD icq_ProxyDestPort;
-       WORD icq_ProxyOurPort;
-       time_t icq_LastKeepAlive;       /* ig */
-       char icq_config[256];           /* ig */
-       struct CtdlICQ_CL *icq_cl;      /* ig */
-       int icq_numcl;                  /* ig */
-};
-
 /* <ig> */
 
-/* ICQROOM is the name of the room in which each user's ICQ configuration
- * and contact lists will be stored.  (It's a personal room.)
- */
-#define ICQROOM                "My ICQ Config"
-
 /* MIME types to use for storing ICQ stuff */
 #define ICQMIME                "application/x-citadel-icq"     /* configuration */
 #define ICQCLMIME      "application/x-citadel-icq-cl"  /* contact list */
@@ -463,7 +434,6 @@ void icq_HandleUserOnline(srv_net_icq_pak pak)
 {
        DWORD remote_uin, new_status, remote_ip, remote_real_ip;
        DWORD remote_port;      /* Why Mirabilis used 4 bytes for port? */
-       icq_ContactItem *ptr;
        char buf[256];
 
        remote_uin = Chars_2_DW(pak.data);
@@ -815,8 +785,8 @@ write out messages to the FD aux
 ***********************************/
 int icq_Connect(const char *hostname, int port)
 {
-       char buf[1024], un = 1;
-       char our_host[256], tmpbuf[256];
+       char buf[1024];
+       char tmpbuf[256];
        int conct, length, res;
        struct sockaddr_in sin, prsin;  /* used to store inet addr stuff */
        struct hostent *host_struct;    /* used in DNS llokup */
@@ -1020,7 +990,6 @@ void icq_HandleServerResponse()
        struct tm *tm_str;
        int s, len;
        char buf[1024];
-       cback acback;
 
        s = icq_SockRead((ThisICQ->icq_Sok), &pak.head, sizeof(pak));
        if (s <= 0) {
@@ -1819,7 +1788,7 @@ void CtdlICQ_Read_Config(void) {
        char icq_rm[ROOMNAMELEN];
        
        strcpy(hold_rm, CC->quickroom.QRname);
-       MailboxName(icq_rm, &CC->usersupp, ICQROOM);
+       MailboxName(icq_rm, &CC->usersupp, CONFIGROOM);
        strcpy(ThisICQ->icq_config, "");
 
        if (getroom(&CC->quickroom, icq_rm) != 0) {
@@ -1830,7 +1799,8 @@ void CtdlICQ_Read_Config(void) {
        /* We want the last (and probably only) config in this room */
        lprintf(9, "We're in <%s> looking for config\n", 
                CC->quickroom.QRname);
-       CtdlForEachMessage(MSGS_LAST, 1, ICQMIME, CtdlICQ_Read_Config_Backend);
+       CtdlForEachMessage(MSGS_LAST, 1, ICQMIME, NULL,
+               CtdlICQ_Read_Config_Backend);
        getroom(&CC->quickroom, hold_rm);
        return;
 }
@@ -1852,7 +1822,7 @@ void CtdlICQ_Write_Config(void) {
        fclose(fp);
 
        /* this handy API function does all the work for us */
-       CtdlWriteObject(ICQROOM, ICQMIME, temp, 1, 0, 1);
+       CtdlWriteObject(CONFIGROOM, ICQMIME, temp, &CC->usersupp, 0, 1, 0);
 
        unlink(temp);
 }
@@ -1882,7 +1852,7 @@ void CtdlICQ_Write_CL(void) {
        fclose(fp);
 
        /* this handy API function does all the work for us */
-       CtdlWriteObject(ICQROOM, ICQCLMIME, temp, 1, 0, 1);
+       CtdlWriteObject(CONFIGROOM, ICQCLMIME, temp, &CC->usersupp, 0, 1, 0);
 
        unlink(temp);
 }
@@ -1943,7 +1913,7 @@ void CtdlICQ_Read_CL(void) {
        char icq_rm[ROOMNAMELEN];
        
        strcpy(hold_rm, CC->quickroom.QRname);
-       MailboxName(icq_rm, &CC->usersupp, ICQROOM);
+       MailboxName(icq_rm, &CC->usersupp, CONFIGROOM);
        strcpy(ThisICQ->icq_config, "");
 
        if (getroom(&CC->quickroom, icq_rm) != 0) {
@@ -1958,7 +1928,8 @@ void CtdlICQ_Read_CL(void) {
        }
 
        /* We want the last (and probably only) list in this room */
-       CtdlForEachMessage(MSGS_LAST, 1, ICQCLMIME, CtdlICQ_Read_CL_Backend);
+       CtdlForEachMessage(MSGS_LAST, 1, ICQCLMIME, NULL,
+               CtdlICQ_Read_CL_Backend);
        getroom(&CC->quickroom, hold_rm);
 }
 
@@ -1994,6 +1965,7 @@ void CtdlICQ_Refresh_Contact_List(void) {
        if (ThisICQ->icq_Sok < 0) return;
        icq_ContClear();
 
+       CtdlICQ_Read_CL();
        if (ThisICQ->icq_numcl) for (i=0; i<ThisICQ->icq_numcl; ++i) {
                if (ThisICQ->icq_cl[i].uin > 0L) {
                        icq_ContAddUser(ThisICQ->icq_cl[i].uin);
@@ -2002,6 +1974,7 @@ void CtdlICQ_Refresh_Contact_List(void) {
        }
 
        icq_SendContactList();
+
 }
 
 
@@ -2025,7 +1998,6 @@ void CtdlICQ_Logout_If_Connected(void) {
  * to log on to the ICQ server.
  */
 void CtdlICQ_Login_If_Possible(void) {
-       char buf[256];
        long uin;
        char pass[256];
 
@@ -2035,13 +2007,10 @@ void CtdlICQ_Login_If_Possible(void) {
        uin = extract_long(ThisICQ->icq_config, 0);
        extract(pass, ThisICQ->icq_config, 1);
 
-       lprintf(9, "Here's my config: %s\n", ThisICQ->icq_config);
-
        if ( (uin > 0L) && (strlen(pass)>0) ) {
                icq_Init(uin, pass);
                if (icq_Connect("icq1.mirabilis.com", 4000) >= 0) {
                        icq_Login(STATUS_ONLINE);
-                       CtdlICQ_Refresh_Contact_List();
                }
        }
 }
@@ -2085,7 +2054,7 @@ void CtdlICQ_session_stopdown_hook(void) {
 void CtdlICQ_after_cmd_hook(void)
 {
        if (ThisICQ->icq_Sok >= 0) {
-               if ( (time(NULL) - ThisICQ->icq_LastKeepAlive) > 90 ) {
+               if ( (time(NULL) - ThisICQ->icq_LastKeepAlive) > 60 ) {
                        icq_KeepAlive();
                        ThisICQ->icq_LastKeepAlive = time(NULL);
                }
@@ -2123,16 +2092,6 @@ void CtdlICQ_session_login_hook(void)
 
 
 
-void cmd_icql(char *argbuf)
-{
-       safestrncpy(ThisICQ->icq_config, argbuf, 256);
-       CtdlICQ_Write_Config();
-       
-       cprintf("%d Ok ... will try to log on to ICQ.\n", OK);
-       CtdlICQ_Login_If_Possible();
-}
-
-
 
 
 /*
@@ -2144,8 +2103,18 @@ void CtdlICQ_Incoming_Message(DWORD uin, BYTE hour, BYTE minute,
        
        char from[256];
        int num_delivered;
+       int i;
 
+       /* Default sender is 'uin@icq' syntax */
        sprintf(from, "%ld@icq", uin);
+
+       /* Use the sender's name if we have it  inthe contact list */
+       if (ThisICQ->icq_numcl) for (i=0; i<ThisICQ->icq_numcl; ++i) {
+               if (uin == ThisICQ->icq_cl[i].uin) {
+                       safestrncpy(from, ThisICQ->icq_cl[i].name, 256);
+               }
+       }
+
        num_delivered = PerformXmsgHooks(from, CC->curr_user, (char *)msg);
        lprintf(9, "Delivered to %d users\n", num_delivered);
 }
@@ -2158,6 +2127,7 @@ void CtdlICQ_InfoReply(unsigned long uin, const char *nick,
 
        struct CtdlICQ_CL *ptr;
        
+       CtdlICQ_Read_CL();
        ptr = CtdlICQ_CLent(uin);
        safestrncpy(ptr->name, nick, 32);
        ptr->status = STATUS_OFFLINE;
@@ -2217,38 +2187,81 @@ int CtdlICQ_Send_Msg(char *from, char *recp, char *msg) {
 
 
 
-void cmd_icqa(char *argbuf) {
+void cmd_cicq(char *argbuf) {
+       char cmd[256];
        long uin;
+       char pass[256];
+       char buf[256];
+       int i;
 
-       uin = extract_long(argbuf, 0);
-       if (uin <= 0L) {
-               cprintf("%d You must supply a uin.\n", ERROR);
+        if (!(CC->logged_in)) {
+                cprintf("%d Not logged in.\n", ERROR + NOT_LOGGED_IN);
+                return;
+        }
+       extract(cmd, argbuf, 0);
+
+       /* "CICQ login" tells us how to log in. */
+       if (!strcasecmp(cmd, "login")) {
+               uin = extract_long(argbuf, 1);
+               extract(pass, argbuf, 2);
+               sprintf(ThisICQ->icq_config, "%ld|%s|", uin, pass);
+               if (uin > 0L) {
+                       CtdlICQ_Write_Config();
+                       cprintf("%d Ok ... will try to log on to ICQ.\n", OK);
+                       CtdlICQ_Login_If_Possible();
+               } else {
+                       cprintf("%d You must supply a UIN.\n", ERROR);
+               }
                return;
        }
 
-       CtdlICQ_Read_CL();
-
-       /* This function is normally used to obtain a relevant pointer, but
-        * it also creates an entry in the contact list if one isn't there.
-        */
-       CtdlICQ_CLent(uin);
+       /* "CICQ getcl" returns the contact list */
+       if (!strcasecmp(cmd, "getcl")) {
+               CtdlICQ_Read_CL();
+               cprintf("%d Your ICQ contact list:\n", LISTING_FOLLOWS);
+               if (ThisICQ->icq_numcl > 0) {
+                       for (i=0; i<ThisICQ->icq_numcl; ++i) {
+                               cprintf("%ld|%s|%s|\n",
+                                       ThisICQ->icq_cl[i].uin,
+                                       ThisICQ->icq_cl[i].name,
+                                       icq_ConvertStatus2Str(
+                                               ThisICQ->icq_cl[i].status)
+                                       );
+                       }
+               }
+               cprintf("000\n");
+               return;
+       }
 
-       /* Save the new contact list and tell the ICQ server about it */
-       CtdlICQ_Write_CL();
-       CtdlICQ_Refresh_Contact_List();
+       /* "CICQ putcl" accepts a new contact list from the client */
+       if (!strcasecmp(cmd, "putcl")) {
+               cprintf("%d Send contact list\n", SEND_LISTING);
+               ThisICQ->icq_numcl = 0;
+               while (client_gets(buf), strcmp(buf, "000")) {
+                       uin = extract_long(buf, 0);
+                       if (uin > 0L) {
+                               CtdlICQ_CLent(uin);
+                       }
+               }
+               CtdlICQ_Write_CL();
+               CtdlICQ_Refresh_Contact_List();
+               return;
+       }
 
-       /* Leave the user clueless as to what happened, because we really
-        * don't know (and this is why I hate asynchronous protocols).
-        */
-       cprintf("%d Ok (maybe)\n", OK);
+       /* "CICQ status" returns the connected/notconnected status */
+       if (!strcasecmp(cmd, "status")) {
+               cprintf("%d %d\n", OK,
+                       ((ThisICQ->icq_Sok >= 0) ? 1 : 0) );
+               return;
+       }
 
-       /* Request more info on this user from the server, which will arrive
-        * at some time in the future.  Maybe.
-        */
-       icq_SendInfoReq(uin);
+       cprintf("%d Invalid subcommand\n", ERROR);
 }
 
 
+
+
+
 /* 
  * During an RWHO command, we want to append our ICQ information.
  */
@@ -2261,7 +2274,7 @@ void CtdlICQ_rwho(void) {
                        0,      /* no session ID */
                        ThisICQ->icq_cl[i].name,
                        icq_ConvertStatus2Str(ThisICQ->icq_cl[i].status),
-                       " ",    /* FIX add host */
+                       ThisICQ->icq_cl[i].host,
                        " ",    /* no client */
                        time(NULL),     /* now? */
                        " ",    /* no last command */
@@ -2280,7 +2293,6 @@ void CtdlICQ_Status_Update(DWORD uin, DWORD status) {
 
 
 void CtdlICQ_Logged(void) {
-       CtdlICQ_Read_CL();
        CtdlICQ_Refresh_Contact_List();
 }
 
@@ -2288,7 +2300,11 @@ void CtdlICQ_Logged(void) {
 void CtdlICQ_UserOnline(DWORD uin, DWORD status, DWORD ip,
                        DWORD port, DWORD realip) {
 
+       DWORD decoded_ip;
+       
        CtdlICQ_Status_Update(uin, status);
+       decoded_ip = ntohl(ip);
+       locate_host(CtdlICQ_CLent(uin)->host, (struct in_addr *)&decoded_ip);
 }
 
 
@@ -2309,9 +2325,8 @@ char *Dynamic_Module_Init(void)
        CtdlRegisterSessionHook(CtdlICQ_session_login_hook, EVT_LOGIN);
        CtdlRegisterSessionHook(CtdlICQ_after_cmd_hook, EVT_CMD);
        CtdlRegisterSessionHook(CtdlICQ_rwho, EVT_RWHO);
-       CtdlRegisterProtoHook(cmd_icql, "ICQL", "Log on to ICQ");
-       CtdlRegisterProtoHook(cmd_icqa, "ICQA", "Add ICQ contact");
-       CtdlRegisterXmsgHook(CtdlICQ_Send_Msg);
+       CtdlRegisterProtoHook(cmd_cicq, "CICQ", "Configure Citadel ICQ");
+       CtdlRegisterXmsgHook(CtdlICQ_Send_Msg, XMSG_PRI_FOREIGN);
 
        /* Tell the code formerly known as icqlib about our callbacks */
        icq_Log = CtdlICQlog;