micq.c
上传用户:ai20ln
上传日期:2007-01-05
资源大小:79k
文件大小:12k
源码类别:

ICQ/即时通讯

开发平台:

Unix_Linux

  1. /*********************************************
  2. **********************************************
  3. This is the main ICQ file. Currently it
  4. logs in and sits in a loop. It can receive
  5. messages and keeps the connection alive.
  6. Use crtl-break to exit.
  7. This software is provided AS IS to be used in
  8. whatever way you see fit and is placed in the
  9. public domain.
  10. Author : Matthew Smith April 19, 1998
  11. Contributors : Nicolas Sahlqvist April 27, 1998
  12.    Ulf Hedlund (guru@slideware.com) April 28, 1998
  13.             Michael Ivey May 4, 1998
  14.             Michael Holzt May 5, 1998
  15. Changes :
  16.    4-28-98 support for WIN32 [UH]
  17.    4-20-98 added variable time_delay between keep_alive packets mds
  18.    4-20-98 added instant message from server support mds
  19.    4-21-98 changed so that long ( 250+ characters ) messages work
  20.             new maximum is ~900 which is hopefully big enough.
  21.             When I know more about udp maybe I can come up with
  22.             a general solution. mds I now think ICQ has a max that is
  23.             smaller than this so everything is ok mds I now think that
  24.             the icq client's maximum is arbitrary and can be ignored :)
  25.    4-23-98 Added beginnings of a user interface
  26.    4-26-98 Changed the version to 0.2a :)
  27.    4-27-98 Nicco added feature to use nick names to log in
  28.    5-05-98 Authorization Messages
  29.    5-13-98 Added time stamps for most things.
  30.    6-17-98 Changed condition on which we should send auto_reply message. Fryslan
  31.    6-18-98 Added different auto reply messages for different status types see also ui.c and util.c Fryslan
  32.    6-20-98 Added an alter command to alter your command names online. Fryslan
  33. **********************************************
  34. **********************************************/
  35. #include "micq.h"
  36. #include "datatype.h"
  37. #include "msg_queue.h"
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <limits.h>
  41. #ifdef _WIN32
  42. #include <conio.h>
  43. #include <io.h>
  44. #include <winsock2.h>
  45. #include <time.h>
  46. #else
  47. #include <unistd.h>
  48. #include <netinet/in.h>
  49. #include <sys/types.h>
  50. #include <sys/stat.h>
  51. #include <sys/socket.h>
  52. #include <arpa/inet.h>
  53. #include <netdb.h>
  54. #include <sys/time.h>
  55. #include <sys/wait.h>
  56. #endif
  57. #include <fcntl.h>
  58. #include <time.h>
  59. #include <stdarg.h>
  60. #include <string.h>
  61. #include <ctype.h>
  62. #include <assert.h>
  63. BYTE Sound = SOUND_ON; /* Beeps on by default */
  64. BYTE Sound_Str[150];  /* the command to run from the shell to play sound files */
  65. BOOL Russian = FALSE; /* Do we do kio8-r <->Cp1251 codeset translation? */
  66. BOOL Logging = TRUE;  /* Do we log messages to ~/micq_log?  This should probably have different levels */
  67. BOOL Color = TRUE; /* Do we use ANSI color? */
  68. BOOL Quit = FALSE;    /* set when it's time to exit the program */
  69. BOOL Verbose = FALSE; /* this is displays extra debuging info */
  70. BOOL serv_mess[ 1024 ]; /* used so that we don't get duplicate messages with the same SEQ */
  71. WORD last_cmd[ 1024 ]; /* command issued for the first 1024 SEQ #'s */
  72. /******************** if we have more than 1024 SEQ this will need some hacking */
  73. WORD seq_num = 1;  /* current sequence number */
  74. DWORD our_ip = 0x0100007f; /* localhost for some reason */
  75. DWORD our_port; /* the port to make tcp connections on */
  76. /************ We don't make tcp connections yet though :( */
  77. DWORD UIN; /* current User Id Number */
  78. BOOL Contact_List = FALSE; /* I think we always have a contact list now */
  79. Contact_Member Contacts[ 100 ]; /* no more than 100 contacts max */
  80. int Num_Contacts=0;
  81. DWORD Current_Status=STATUS_OFFLINE;
  82. DWORD last_recv_uin=0;
  83. char passwd[100];
  84. char server[100];
  85. DWORD set_status;
  86. DWORD remote_port;
  87. BOOL Done_Login=FALSE;
  88. BOOL auto_resp=FALSE;
  89. char auto_rep_str_dnd[450] = { "Don't page me, my head is hurting!" };
  90. char auto_rep_str_away[450] = { "I told you I wasn't here!" };
  91. char auto_rep_str_na[450] = { "Working, working always working..." };
  92. char auto_rep_str_occ[450] = { "I am working on opening this beer so I am busy." };
  93. char auto_rep_str_inv[450] = { "So you can see me, so you can't!" };
  94. char message_cmd[16];
  95. char info_cmd[16];
  96. char quit_cmd[16];
  97. char reply_cmd[16];
  98. char again_cmd[16];
  99. char add_cmd[16];
  100. char list_cmd[16];
  101. char away_cmd[16];
  102. char na_cmd[16];
  103. char dnd_cmd[16];
  104. char online_cmd[16];
  105. char occ_cmd[16];
  106. char ffc_cmd[16];
  107. char inv_cmd[16];
  108. char status_cmd[16];
  109. char auth_cmd[16];
  110. char auto_cmd[16];
  111. char change_cmd[16];
  112. char search_cmd[16];
  113. char save_cmd[16];
  114. char alter_cmd[16];
  115. char msga_cmd[16];
  116. char url_cmd[16];
  117. char update_cmd[16];
  118. unsigned int next_resend;
  119. /*/////////////////////////////////////////////
  120. // Connects to hostname on port port
  121. // hostname can be DNS or nnn.nnn.nnn.nnn
  122. // write out messages to the FD aux */
  123. int Connect_Remote( char *hostname, int port, FD_T aux )
  124. {
  125.    int conct, length;
  126.    int sok;
  127.    struct sockaddr_in sin;  /* used to store inet addr stuff */
  128.    struct hostent *host_struct; /* used in DNS lookup */
  129. #if 1
  130. sin.sin_addr.s_addr = inet_addr( hostname ); 
  131.    if ( sin.sin_addr.s_addr  == -1 ) /* name isn't n.n.n.n so must be DNS */
  132. #else
  133. if ( inet_aton( hostname, &sin.sin_addr )  == 0 ) /* checks for n.n.n.n notation */
  134. #endif
  135. {
  136.    host_struct = gethostbyname( hostname );/* name isn't n.n.n.n so must be DNS */
  137.       if ( host_struct == NULL )
  138.       {
  139.          if ( Verbose )
  140.          {
  141.             M_fdprint( aux, "Shakespeare couldn't spell why should I?n" );
  142.             M_fdprint( aux, " Especially something like %sn", hostname );
  143.             /*herror( "Can't find hostname" );*/
  144.          }
  145.          return 0;
  146.       }
  147.    sin.sin_addr = *((struct in_addr *)host_struct->h_addr);
  148.    }
  149. sin.sin_family = AF_INET; /* we're using the inet not appletalk*/
  150. sin.sin_port = htons( port ); /* port */
  151. sok = socket( AF_INET, SOCK_DGRAM, 0 );/* create the unconnected socket*/
  152.    if ( sok == -1 ) 
  153.    {
  154.       perror( "Socket creation failed" );
  155.       exit( 1 );
  156.    }   
  157.    if ( Verbose )
  158.    {
  159.       M_fdprint( aux, "Socket created attempting to connectn" );
  160.    }
  161. conct = connect( sok, (struct sockaddr *) &sin, sizeof( sin ) );
  162. if ( conct == -1 )/* did we connect ?*/
  163. {
  164.       if ( Verbose )
  165.       {
  166.        M_fdprint( aux, " Conection Refused on port %d at %sn", port, hostname );
  167.          #ifdef FUNNY_MSGS
  168.             M_fdprint( aux, " D'oh!n" );
  169.          #endif
  170.        perror( "connect" );
  171.       }
  172.    return 0;
  173. }
  174.    length = sizeof( sin ) ;
  175.    getsockname( sok, (struct sockaddr *) &sin, &length );
  176.    our_ip = sin.sin_addr.s_addr;
  177.    our_port = sin.sin_port;
  178.    if (Verbose )
  179.    {
  180.       #ifdef FUNNY_MSGS
  181.          M_fdprint( aux, "Our port is %d, take her to sea Mr. Mordoch.n", ntohs( sin.sin_port ) );
  182.       #else
  183.          M_fdprint( aux, "The port that will be used for tcp ( not yet implemented ) is %dn", ntohs( sin.sin_port ) );
  184.       #endif
  185.    }
  186.    if ( Verbose )
  187.    {
  188.       M_fdprint( aux, "Connected to %s, waiting for responsen", hostname );
  189.    }
  190.    return sok;
  191. }
  192. /******************************************
  193. Handles packets that the server sends to us.
  194. *******************************************/
  195. void Handle_Server_Response( SOK_T sok )
  196. {
  197.    srv_net_icq_pak pak;
  198.    int s;
  199.    
  200.    s = SOCKREAD( sok, &pak.head.ver, sizeof( pak ) - 2  );
  201.    if ( s < 0 )
  202.     return;
  203. #if 0    /* V4 testing */
  204.        M_print( CLIENTCOL "nThe response was %04Xt", Chars_2_Word( pak.head.cmd ) );
  205.        M_print( "The version was %Xt", Chars_2_Word( pak.head.ver ) );
  206.        Time_Stamp();
  207.        M_print( "nThe SEQ was %04Xt", Chars_2_Word( pak.head.seq ) );
  208.        len = s - ( sizeof( pak.head ) - 2 );
  209.        M_print( "The size was %dn", len );
  210.        if ( Verbose )
  211.        {
  212.             Hex_Dump( pak.data, len );
  213.        }
  214.        M_print( NOCOL "n" );
  215.        Prompt();
  216.        ack_srv( sok, Chars_2_Word( pak.head.seq ) ); /* fake like we know what we're doing*/
  217.    return;
  218. #endif
  219.       
  220.    if ( ( serv_mess[ Chars_2_Word( pak.head.seq ) ] ) && 
  221.       ( Chars_2_Word( pak.head.cmd ) != SRV_NEW_UIN ) )
  222.    {
  223.       if ( Chars_2_Word( pak.head.cmd ) != SRV_ACK ) /* ACKs don't matter */
  224.       {
  225.          if ( Verbose )
  226.             M_print( "nIgnored a message cmd  %04xn", Chars_2_Word( pak.head.cmd )  );
  227.          ack_srv( sok, Chars_2_Word( pak.head.seq ) ); /* LAGGGGG!! */
  228.          return;
  229.       }
  230.    }
  231.    if ( Chars_2_Word( pak.head.cmd ) != SRV_ACK )
  232.    {
  233.       serv_mess[ Chars_2_Word( pak.head.seq ) ] = TRUE;
  234.       ack_srv( sok, Chars_2_Word( pak.head.seq ) );
  235.    }
  236.    Server_Response( sok, pak.data, s - ( sizeof( pak.head ) - 2 ), 
  237.       Chars_2_Word( pak.head.cmd ), Chars_2_Word( pak.head.ver ),
  238.       Chars_2_Word( pak.head.seq ), Chars_2_DW( pak.head.UIN ) );
  239. }
  240. /**********************************************
  241. Verifies that we are in the correct endian
  242. ***********************************************/
  243. void Check_Endian( void )
  244. {
  245.    int i;
  246.    char passwd[10];
  247.    
  248.    passwd[0] = 1;
  249.    passwd[1] = 0;
  250.    passwd[2] = 0;
  251.    passwd[3] = 0;
  252.    passwd[4] = 0;
  253.    passwd[5] = 0;
  254.    passwd[6] = 0;
  255.    passwd[7] = 0;
  256.    passwd[8] = 0;
  257.    passwd[9] = 0;
  258.    i = *  ( DWORD *) passwd;
  259.    if ( i == 1 )
  260.    {
  261.       M_print( "Using intel byte ordering.n" );
  262.    }
  263.    else
  264.    {
  265.       M_print( "Using motorola byte ordering.n" );
  266.    }
  267. }
  268. /******************************
  269. Main function connects gets UIN
  270. and passwd and logins in and sits
  271. in a loop waiting for server responses.
  272. ******************************/
  273. int main( int argc, char *argv[] )
  274. {
  275.    int sok;
  276.    int i;
  277.    int next;
  278.    int time_delay = 120;
  279.    struct timeval tv;
  280.    fd_set readfds;
  281. #ifdef _WIN32
  282.    WSADATA wsaData;
  283. #endif
  284.    M_print( SERVCOL "Matt's ICQ clone " NOCOL "compiled on %s %sn" SERVCOL " Version " MICQ_VERSION NOCOL "n", __TIME__, __DATE__ );
  285. #ifdef FUNNY_MSGS
  286.    M_print( "No Mirabilis client was maimed, hacked, tortured, sodomized or otherwise harmednin the making of this utility.n" );
  287. #else
  288.    M_print( "This program was made without any help from Mirabilis or their consent.n" );
  289.    M_print( "No reverse engineering or decompilation of any Mirabilis code took placento make this program.n" );
  290. #endif
  291.    Get_Config_Info();
  292.    if ( !strcmp( passwd,"" ) )
  293.    {
  294.       M_print( "Enter password : " );
  295.       fflush( stdout );
  296.       Echo_Off();
  297.       M_fdnreadln(STDIN, passwd, sizeof(passwd));
  298.       Echo_On();
  299.    }
  300.    memset( serv_mess, FALSE, 1024 );
  301.    Initialize_Msg_Queue();
  302.    if (argc > 1 )
  303.    {
  304.       for ( i=1; i< argc; i++ )
  305.       {
  306.          if ( argv[i][0] != '-' )
  307.          ;
  308.          else if ( (argv[i][1] == 'v' ) || (argv[i][1] == 'V' ) )
  309.          {
  310.             Verbose++;
  311.          }
  312.       }
  313.    }
  314.    Check_Endian();
  315. #ifdef _WIN32
  316.    i = WSAStartup( 0x0101, &wsaData );
  317.    if ( i != 0 ) {
  318. #ifdef FUNNY_MSGS
  319. perror("Windows Sockets broken blame Bill -");
  320. #else
  321. perror("Sorry, can't initialize Windows Sockets...");
  322. #endif
  323.     exit(1);
  324.    }
  325. #endif
  326.    sok = Connect_Remote( server, remote_port, STDERR );
  327.    if ( ( sok == -1 ) || ( sok == 0 ) ) 
  328.    {
  329.     M_print( "Couldn't establish connectionn" );
  330.     exit( 1 );
  331.    }
  332.    Login( sok, UIN, &passwd[0], our_ip, our_port, set_status );
  333.    next = time( NULL );
  334.    next += 120;
  335.    next_resend = 10;
  336.    Prompt();
  337.    for ( ; !Quit; )
  338.    {
  339. #ifdef UNIX
  340.   tv.tv_sec = 2;
  341.       tv.tv_usec = 500000;
  342. #else
  343.   tv.tv_sec = 0;
  344.       tv.tv_usec = 100000;
  345. #endif
  346.       FD_ZERO(&readfds);
  347.       FD_SET(sok, &readfds);
  348. #ifndef _WIN32
  349.       FD_SET(STDIN, &readfds);
  350. #endif
  351.       /* don't care about writefds and exceptfds: */
  352.       select(sok+1, &readfds, NULL, NULL, &tv);
  353.       if (FD_ISSET(sok, &readfds))
  354.           Handle_Server_Response( sok );
  355. #if _WIN32
  356.   else if (_kbhit()) /* sorry, this is a bit ugly...   [UH]*/
  357. #else      
  358.   else if (FD_ISSET( STDIN, &readfds ) )
  359. #endif
  360.       {
  361.          Get_Input( sok );
  362.       }
  363.       if ( time( NULL ) > next )
  364.       {
  365.          next = time( NULL ) + time_delay;
  366.          Keep_Alive( sok );
  367.       }
  368.       if ( time( NULL ) > next_resend )
  369.       {
  370.         Do_Resend( sok );
  371.       }
  372. #ifdef UNIX
  373.       while(waitpid(-1,NULL,WNOHANG) > 0); /* clean up child processes */
  374. #endif
  375.    }
  376.    Quit_ICQ( sok );
  377.    return 0;
  378. }
  379.