/*

STRICQ - An Amiga, MUI Based, ICQ Clone.
Copyright (C) 1998-2000 Douglas F. McLaughlin

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 2
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

Douglas F. McLaughlin - stricq@owlnet.net

*/

#include <sys/types.h>

#include <ctype.h>
#include <math.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#include <exec/types.h>
#include <exec/memory.h>

#include <devices/timer.h>

#include <intuition/screens.h>

#include <libraries/asl.h>
#include <libraries/asyncio.h>
#include <libraries/icq.h>
#include <libraries/openurl.h>

#include <bsdsocket/socketbasetags.h>

#include <rexx/storage.h>

#include <sys/dir.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>

#include <utility/date.h>

#include <proto/asyncio.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/miami.h>
#include <proto/openurl.h>
#include <proto/utility.h>

#include "STRICQMUI.h"
#include "STRICQ_Cat.h"
#include "cmd_codes.h"
#include "countries.h"
#include "codes.h"

#include <proto/socket.h>

APTR __asm AddOffline(REG(a2) APTR, REG(a1) struct Contact *);
void __asm RemOffline(REG(a2) APTR, REG(a1) struct Contact *);
LONG __asm CmpOffline(REG(a1) struct Contact *, REG(a2) struct Contact *);
void __asm DisplayOffline(REG(a2) char **, REG(a1) struct Contact *);

APTR __asm AddLog(REG(a2) APTR, REG(a1) struct ICQLog *);
void __asm RemLog(REG(a2) APTR, REG(a1) struct ICQLog *);
LONG __asm CmpLog(REG(a1) struct ICQLog *, REG(a2) struct ICQLog *);
void __asm DisplayLog(REG(a2) char **, REG(a1) struct ICQLog *);

APTR __asm AddMsg(REG(a2) APTR, REG(a1) struct ICQMessage *);
void __asm RemMsg(REG(a2) APTR, REG(a1) struct ICQMessage *);
LONG __asm CmpMsg(REG(a1) struct ICQMessage *, REG(a2) struct ICQMessage *);
void __asm DisplayMsg(REG(a2) char **, REG(a1) struct ICQMessage *);

APTR __asm AddActy(REG(a2) APTR, REG(a1) struct Activity *);
void __asm RemActy(REG(a2) APTR, REG(a1) struct Activity *);
LONG __asm CmpActy(REG(a1) struct Activity *, REG(a2) struct Activity *);
void __asm DisplayActy(REG(a2) char **, REG(a1) struct Activity *);

APTR __asm AddSock(REG(a2) APTR, REG(a1) struct Sockets *);
void __asm RemSock(REG(a2) APTR, REG(a1) struct Sockets *);
LONG __asm CmpSock(REG(a1) struct Sockets *, REG(a2) struct Sockets *);
void __asm DisplaySock(REG(a2) char **, REG(a1) struct Sockets *);

APTR __asm AddCols(REG(a2) APTR, REG(a1) struct Column *);
void __asm RemCols(REG(a2) APTR, REG(a1) struct Column *);
LONG __asm CmpCols(REG(a1) struct Column *, REG(a2) struct Column *);
void __asm DisplayCols(REG(a2) char **, REG(a1) struct Column *);

APTR __asm AddIgnore(REG(a2) APTR, REG(a1) struct IgnoreUIN *);
void __asm RemIgnore(REG(a2) APTR, REG(a1) struct IgnoreUIN *);
LONG __asm CmpIgnore(REG(a1) struct IgnoreUIN *, REG(a2) struct IgnoreUIN *);
void __asm DisplayIgnore(REG(a2) char **, REG(a1) struct IgnoreUIN *);

APTR __asm AddAddUIN(REG(a2) APTR, REG(a1) struct MSG_AddUIN *);
void __asm RemAddUIN(REG(a2) APTR, REG(a1) struct MSG_AddUIN *);
LONG __asm CmpAddUIN(REG(a1) struct MSG_AddUIN *, REG(a2) struct MSG_AddUIN *);
void __asm DisplayAddUIN(REG(a2) char **, REG(a1) struct MSG_AddUIN *);

APTR __asm AddErr(REG(a2) APTR, REG(a1) struct ErrorMsgs *);
void __asm RemErr(REG(a2) APTR, REG(a1) struct ErrorMsgs *);
LONG __asm CmpErr(REG(a1) struct ErrorMsgs *, REG(a2) struct ErrorMsgs *);
void __asm DisplayErr(REG(a2) char **, REG(a1) struct ErrorMsgs *);

extern APTR __asm AddFile(REG(a2) APTR, REG(a1) struct FileList *);
extern void __asm RemFile(REG(a2) APTR, REG(a1) struct FileList *);
extern LONG __asm CmpFile(REG(a1) struct FileList *, REG(a2) struct FileList *);
extern void __asm DisplayFile(REG(a2) char **, REG(a1) struct FileList *);

void __asm GetUINInfo(REG(a2) APTR);
void __asm AddContact(REG(a2) APTR);
void __asm ConnectICQ(REG(a2) APTR);
void __asm DisconnectICQ(REG(a2) APTR);
void __asm ChangePW(REG(a2) APTR);
void __asm SendMessage(REG(a2) APTR);
void __asm SendMsg2ICQ(REG(a2) APTR);
void __asm SendMsg2ICQa(REG(a2) APTR);
void __asm AddUpdate(REG(a2) APTR);
void __asm SetQuickTo(REG(a2) APTR);
void __asm ChangeMyStatus(REG(a2) APTR);
void __asm SavePrefs(REG(a2) APTR);
void __asm LoadPrefs(REG(a2) APTR);
void __asm GoURL(REG(a2) APTR);
void __asm AddServer(REG(a2) APTR);
void __asm OpenWin(REG(a2) APTR);
void __asm ViewHistory(REG(a2) APTR);
void __asm SendUInfo1(REG(a2) APTR);
void __asm SendUInfo2(REG(a2) APTR);
void __asm NewUIN(REG(a2) APTR);
void __asm MakeFilenames(REG(a2) APTR);
void __asm ChangeMyUIN(REG(a2) APTR);
void __asm SaveMsgWin(REG(a2) APTR);
void __asm PrepFunctionWin(REG(a2) APTR);
void __asm NewUserWin(REG(a2) APTR);
void __asm SaveContactJump(REG(a2) APTR);
void __asm LoadContactJump(REG(a2) APTR);
void __asm LoadHistory(REG(a2) APTR);
void __asm SaveHistory(REG(a2) APTR);
void __asm DeleteHistory(REG(a2) APTR);
void __asm RemoveContact(REG(a2) APTR);
void __asm SendChatReq(REG(a2) APTR);
void __asm Accept(REG(a2) APTR);
void __asm Refuse(REG(a2) APTR);
void __asm OpenChatReqWin(REG(a2) APTR);
void __asm EndChat(REG(a2) APTR);
void __asm Add2Ignore(REG(a2) APTR);
void __asm ForwardMsg(REG(a2) APTR);
void __asm SetCountry(REG(a2) APTR);
void __asm GetAddUINInfo(REG(a2) APTR);
void __asm ShareContacts(REG(a2) APTR);
void __asm SaveErrors(REG(a2) APTR);
void __asm SetUserVisPrefs(REG(a2) APTR);
void __asm OpenEditIgnore(REG(a2) APTR);
void __asm SetIgnoreEdits(REG(a2) APTR);
void __asm ChangeZodiac(REG(a2) APTR);
void __asm ResetSockets(REG(a2) APTR);

extern void __asm OpenFileDirectWin(REG(a2) APTR);

void fail(struct ObjApp *, char *);

ULONG __asm MyDispatcher(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg);
ULONG __asm TimeDispatcher(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg);
ULONG __asm ColorDispatcher(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg);
ULONG __asm ColsDispatcher(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg);

ULONG PORT_NewUDP(struct IClass *, Object *, Msg);
ULONG PORT_Dispose(struct IClass *, Object *, Msg);
ULONG PORT_Setup(struct IClass *, Object *, Msg);
ULONG PORT_Cleanup(struct IClass *, Object *, Msg);
ULONG PORT_Trigger_cl(struct IClass *, Object *, Msg);

ULONG TIME_New(struct IClass *, Object *, Msg);
ULONG TIME_Set(struct IClass *, Object *, Msg);
ULONG TIME_Dispose(struct IClass *, Object *, Msg);
ULONG TIME_Setup(struct IClass *, Object *, Msg);
ULONG TIME_Cleanup(struct IClass *, Object *, Msg);
ULONG TIME_Trigger_cl(struct IClass *, Object *, Msg);
ULONG TIME_Trigger_cl1(struct IClass *, Object *, Msg);
ULONG SendAFile(struct IClass *cl, Object *obj, Msg msg);
ULONG ParseUDPCommands(struct IClass *cl, Object *obj, Msg msg);

ULONG COLOR_Set(struct IClass *, Object *, Msg);
ULONG COLOR_Setup(struct IClass *, Object *, Msg);
ULONG COLOR_Cleanup(struct IClass *, Object *, Msg);
ULONG COLOR_Draw(struct IClass *, Object *, struct MUIP_Draw *);

ULONG COLS_mDragQuery(struct IClass *, Object *, struct MUIP_DragDrop *msg);
ULONG COLS_mDragDrop(struct IClass *, Object *, struct MUIP_DragDrop *msg);

int send_udp_pkt(void *, int, ULONG);
int recv_udp_pkt(void *, int, struct Sockets *);
void revmemcpy(char *, char *, int);
void ParseCmd(UWORD, UWORD, char *, int);
void SendContacts(ULONG, UWORD);
void ParseMessage(UWORD, char *, ULONG, UWORD);
char *ParseMsgHdr(char *, struct Contact *);
void SendAMessage(APTR, ULONG, char *, UWORD, UBYTE, int);
char *GetNick(ULONG);
void ContactsOffline(void);
BOOL OpenICQSocket(void);
void StoreMessage(struct ICQMessage *, ULONG, UWORD);
BOOL MyCreateDir(char *);
BOOL CreateUserWin(ULONG);
struct Contact *GetContact(ULONG);
struct Sockets *GetSocketFmSocket(UWORD);
struct Sockets *GetSocketFmPort(UWORD);
void UpdateUserWin(struct Contact *);
struct ColorText *GetStatus(ULONG);
void SaveContact(ULONG);
BOOL LoadContact(ULONG);
void SaveAllContacts(void);
int  recv_tcp_pkt(char *, struct Sockets *);
int  recv_chat(char *, UWORD);
void ParseTCPCmd(char *, int, UWORD);
BOOL SendTCPMessage(ULONG, char *, UWORD, UWORD, UWORD, ULONG, char *, ULONG, UWORD, ULONG);
LONG OpenTCPSocket(struct Contact *, UBYTE, ULONG, ULONG);
void SendTCPInit(UWORD, struct Contact *, ULONG);
void PrepNewContact(struct Contact *);
void DelSockets(UWORD);
struct Sockets *GetSocketFmContact(struct Contact *, UBYTE);
char *FindCountryName(UWORD);
void SendMessage2Script(char *, ULONG, UWORD);
void SendPing(void);
void AddUser2CList(struct Contact *);
void CFWinOpen(ULONG, char *, UWORD, LONG, UWORD);
ULONG OpenTCPListen(UBYTE);
void SendChatInit(UWORD);
void ParseChatPkt(char *, int, UWORD);
void DoChatMode(char *, int, UWORD);
void ReDrawCList(void);
BOOL CheckIgnore(ULONG);
void Add2Log(UBYTE, struct UDP_Header *, BOOL, UWORD, char *);
char *PreParseMsg(ULONG, UWORD, char *);
UWORD MakeBeats(time_t);
void HandleError(UBYTE, char *, ...);
void PrepTCPMessage(struct TCP_Message *, ULONG);
LONG SendTCPPacket(ULONG, UWORD, char *, UWORD, UWORD);
void SendTCPMsgViaUDP(ULONG);
void SendDelayedTCP(struct Sockets *);
void HandleACK(char *, UWORD);
void InfoView(APTR, UBYTE);
void InfoRefresh(APTR, UBYTE);
void InfoGrabMe(APTR, UBYTE);
void ChangeZodiacPic(struct Contact *, BOOL);
void FreeUser(struct Contact *);
BOOL RefreshUInfo(char **, char *);
void DeleteUIN(ULONG);

extern void ParseFilePkt(char *, int, UWORD);
extern BOOL StartFileXFer(struct Contact *, BOOL);
extern void EndFile(struct Contact *);
extern ULONG GetSize(struct FileList *files);
extern void SendFileInit(UWORD, struct Contact *);


struct ICQLog {
  ULONG UIN;
  ULONG Seq;
  UWORD Se2;
  UWORD Cmd;
  BOOL  Ack;
  UWORD Len;
  UBYTE Resend;
  time_t Timehack;
  UBYTE *Pkt;
};

struct ICQMessage {
  ULONG  UIN;
  time_t Timehack;
  UWORD Type;
  char  *Msg;
};

struct Activity {
  ULONG UIN;
  ULONG Status;
  time_t Timehack;
};

struct MUIP_PT_AddApp {
  ULONG MethodID;
  Object *App;
};

struct Column {
  char *Name;
  char *COL;
};


struct Colors Pens;

struct Library *MUIMasterBase, *SocketBase, *AsyncIOBase, *MiamiBase, *OpenURLBase;

struct ObjApp *app;

BOOL Online, TryAgain, SocketOpen, FirstLogin, NewUser, GrabMyStats, OpenURL, ARexx, Reconnecting, OldPrefsFmt;

/* Fonctions necessary for Localization of the Menus&Arrays... */
extern void localise_array(char *array[])
{
    char **x;

    for(x=array;*x;x++)
        *x = (char *)((struct FC_String *)(*x))->msg;
}

char version_string[] = "$VER: STRICQ 0.1729 (12.07.00)\n\nCopyright © 1998-2000 Douglas F. McLaughlin&Nogfx\nICQ Protocol Copyright © 1996 Mirabilis LTD.\n\nAll Rights Reserved.";

extern char *UPages[] = {
    (char*)_msgUPDialogue,
    (char*)_msgUPSend,
    (char*)_msgUPUsrInfo,
    (char*)_msgUPHistory,
NULL
};

// char *UPages[]   = {"Dialogue", "Send URL", "User Info", "History", NULL};


extern char *UPagesUI[] = {
    (char*)_msgUPUIBasic,
    (char*)_msgUPUIExtended,
    (char*)_msgUPUIPrefs,
NULL
};

// char *UPagesUI[] = {"Basic Info", "Extended Info", "Prefs", NULL};


extern char *InfoPages[] = {
    (char*)_msgInfoMain,
    (char*)_msgInfoHome,
    (char*)_msgInfoMore,
    (char*)_msgInfoAbout,
    (char*)_msgInfoPrefs,
NULL
};


// char *InfoPages[] = {"Main", "Home", "More", "Info/About", "Prefs", NULL};

/*
extern char *Columns[][2] = {
    {(char*)_msgColLamp1, (char*)_msgColLamp2},
    {(char*)_msgColUIN1, (char*)_msgColUIN2},
    {(char*)_msgColStatus1, (char*)_msgColStatus2},
    {(char*)_msgColNick1, (char*)_msgColNick2},
    {(char*)_msgColName1, (char*)_msgColName2},
    {(char*)_msgColEMail1, (char*)_msgColEMail2},
    {(char*)_msgColAuth1, (char*)_msgColAuth2},
    {(char*)_msgColIP1, (char*)_msgColIP2},
    {(char*)_msgColPort1, (char*)_msgColPort2},
    {NULL,NULL}
};*/

  char *Columns[][2] = {
  {"Message Lamp", "COL=0"},
  {"UIN", "COL=1"},
  {"Statut", "COL=2"},
  {"Surnom", "COL=3"},
  {"Nom", "COL=4"},
  {"Adresse Electronique", "COL=5"},
  {"Autorisation", "COL=6"},
  {"IP", "COL=8"},
  {"Port", "COL=9"},
  {NULL, NULL}
};

UBYTE ChatColors[16][3] = {
  {0x00, 0x00, 0x00}, // Black
  {0x80, 0x00, 0x00}, // Maroon
  {0x00, 0x80, 0x00}, // Green
  {0x80, 0x80, 0x00}, // Olive
  {0x00, 0x00, 0x80}, // Navy
  {0x80, 0x00, 0x80}, // Purple
  {0x00, 0x80, 0x80}, // Teal
  {0x80, 0x80, 0x80}, // Gray
  {0xc0, 0xc0, 0xc0}, // Silver
  {0xff, 0x00, 0x00}, // Red
  {0x00, 0xff, 0x00}, // Lime
  {0xff, 0xff, 0x00}, // Yellow
  {0x00, 0x00, 0xff}, // Blue
  {0xff, 0x00, 0xff}, // Fuchsia
  {0x00, 0xff, 0xff}, // Aqua
  {0xff, 0xff, 0xff}, // White
};

extern char *ChatColorNames[] = {
    (char*)_msgChatColor1,
    (char*)_msgChatColor2,
    (char*)_msgChatColor3,
    (char*)_msgChatColor4,
    (char*)_msgChatColor5,
    (char*)_msgChatColor6,
    (char*)_msgChatColor7,
    (char*)_msgChatColor8,
    (char*)_msgChatColor9,
    (char*)_msgChatColor10,
    (char*)_msgChatColor11,
    (char*)_msgChatColor12,
    (char*)_msgChatColor13,
    (char*)_msgChatColor14,
    (char*)_msgChatColor15,
    (char*)_msgChatColor16,
NULL
};

// char *ChatColorNames[] = {"Black", "Maroon", "Green", "Olive", "Navy", "Purple", "Teal", "Gray",
//                          "Silver", "Red", "Lime", "Yellow", "Blue", "Fuchsia", "Aqua", "White", NULL};

char contact_fl[MAXNAMLEN], config_fl[MAXNAMLEN], colors_fl[MAXNAMLEN], currentdir[MAXNAMLEN], sbuf[UDPBUFLEN], rbuf[UDPBUFLEN];
char server_fl[MAXNAMLEN], logdir_fl[MAXNAMLEN], lastuser_fl[MAXNAMLEN], uin_fl[MAXNAMLEN], userstat_fl[MAXNAMLEN];
char userdir_fl[MAXNAMLEN], tbuf[TCPBUFLEN], maintitle[50], tmpmsg_fl[MAXNAMLEN], UDP_Buf[UDPBUFLEN], err_buf[128];

extern char splash[];

enum {CHAT_NO=1, CHAT_REQUESTING, CHAT_MODE};

enum {INFO_VIEW=1, INFO_REFRESH, INFO_GRABME, INFO_BASIC, INFO_EXTENDED, INFO_META_HOME, INFO_META_WORK, INFO_META_MORE,
      INFO_META_ABOUT, INFO_META_INTERESTS, INFO_META_AFFILIATIONS, INFO_META_URLCATEGORY};

int found, online_cnt, offmsg_cnt, contacts_cnt;
int maxfd = -1;

fd_set rset, wset;

LONG PORT_signal, PORT_mask, __stack = 32768, WhichLamp, cmap[NUM_CHAT_COLORS];

time_t LastSend = 0;

UWORD info_seq = 1, extinfo_seq = 1, metainfo_seq = 1, srch_seq = 1, pw_seq = 1, login_seq = 2, chguinfo_seq = 1;

ULONG TCP_Seq = 0xfffffffe, UserInfoReqID[3];

ULONG AsyncBuf = 0x0900, httpbuf = 2048, mask, events, URLMsg_cnt = 0, SrvrMsg_cnt = 0, FileListen = 0;

ULONG Codes[] = {STATUS_ONLINE, STATUS_ONLINE|STATUSF_INVISIBLE, STATUS_NA, STATUS_ONLINE|STATUSF_CHAT, STATUS_ONLINE|STATUSF_HIGH, STATUS_AWAY, STATUS_DND, STATUS_OFFLINE};

UWORD TCPCodes[] = {TCP_STATUS_ONLINE, TCP_STATUS_ONLINE, TCP_STATUS_NA, TCP_STATUS_ONLINE, TCP_STATUS_OCCUPIED, TCP_STATUS_AWAY, TCP_STATUS_DND};

struct hostent *nameinfo;

struct UDP_Header Header;

int main(int argc, char *argv[])

{

struct AsyncFile *loadfh;
struct Column   Col;
struct Process *pr;
struct Sockets *socks;
struct Window  *mywin = NULL;

APTR oldwinptr;

BOOL *auto_ch = NULL;

BPTR olddir;

char line[1024], *cmd;

int i;

LONG index = 0;

ULONG sigs = 0, uin = 0, total = 0, total2 = 0, red, grn, blu;

Header.Version = 0x0002;
Header.Sequence2 = 0;

online_cnt = offmsg_cnt = contacts_cnt = 0;

ARexx = GrabMyStats = TryAgain = Online = SocketOpen = NewUser = Reconnecting = OldPrefsFmt = FALSE;

PORT_signal = PORT_mask = 0;

OpenURL = FirstLogin = TRUE;

localise_array(UPages);
localise_array(InfoPages);
localise_array(UPagesUI);
localise_array(ChatColorNames);

if (!(MUIMasterBase = OpenLibrary(MUIMASTER_NAME,MUIMASTER_VMIN))) fail(NULL,"Failed to open "MUIMASTER_NAME".");
if (!(AsyncIOBase   = OpenLibrary("asyncio.library",39)))  fail(NULL,"Could not open asyncio.library v39.");
if (!(SocketBase    = OpenLibrary("bsdsocket.library",3))) fail(NULL,"Could not open bsdsocket.library v3.");
if (!(OpenURLBase   = OpenLibrary("openurl.library",0))) OpenURL = FALSE;

if ((olddir = GetProgramDir())) if (!NameFromLock(olddir,currentdir,MAXNAMLEN)) strcpy(currentdir,"PROGDIR:");

if (LASTCHAR(currentdir) != ':') strcat(currentdir,"/");

if (!(app = (struct ObjApp *)CreateApp(currentdir))) fail(NULL,"Failed to create application.");

if (strlen(splash)) set(app->WI_Splash,MUIA_Window_Open,TRUE);

// set(app->WI_Progress,MUIA_Window_Open,TRUE);

DoMethod(app->TX_Port  ,PORT_AddApp,app->App);
DoMethod(app->TX_Timer ,TIME_AddApp,app->App);
DoMethod(app->TX_Timer1,TIME_AddApp,app->App);
DoMethod(app->CC_Parse ,TIME_AddApp,app->App);

for(i = 0; i < NUM_STATUS_COLORS; i++) DoMethod(app->PP_StatusColors[i],MUIM_Pendisplay_SetMUIPen,MPEN_SHINE);

for(i = 0; i < NUM_CHAT_COLORS; i++) {
  red = ChatColors[i][0]<<24;
  grn = ChatColors[i][1]<<24;
  blu = ChatColors[i][2]<<24;
  DoMethod(app->PP_ChatColors[i],MUIM_Pendisplay_SetRGB,red,grn,blu);
}

sprintf(uin_fl,"%sUsers/",currentdir);

set(app->DL_UINList,MUIA_Dirlist_Directory,uin_fl);

if (argc < 2) {
  sprintf(lastuser_fl,"%sLastUser",currentdir);
  if (loadfh = OpenAsync(lastuser_fl,MODE_READ,AsyncBuf)) {
    ReadAsync(loadfh,line,sizeof(line));
    sscanf(line,"%ld",&uin);
    CloseAsync(loadfh);
  }
}
else StrToLong(argv[1],(LONG *)&uin);

set(app->STR_ICQUIN,MUIA_String_Integer,uin);

Header.UIN = uin;

LoadPrefs(NULL);

//ChangeZodiacPic(NULL,TRUE);

get(app->LV_ColsStore,MUIA_NList_Entries,&total);
get(app->LV_ColsUse,MUIA_NList_Entries,&total2);

if (total == 0 && total2 == 0) {
  for(i = 0; Columns[i][0]; i++) {
    Col.Name = Columns[i][0];
    Col.COL = Columns[i][1];
    DoMethod(app->LV_ColsUse,MUIM_NList_InsertSingle,&Col,MUIV_NList_Insert_Bottom);
  }
}

ReDrawCList();

set(app->TX_About,MUIA_Text_Contents,version_string+6);

get(app->CH_MsgTime,MUIA_Selected,&auto_ch);
if (!auto_ch) set(app->LV_Msgs,MUIA_NList_Format,"COL=0 BAR,COL=2");

get(app->CH_OpenMsg,MUIA_Selected,&auto_ch);
if (auto_ch) set(app->WI_Message,MUIA_Window_Open,TRUE);

set(app->TX_Color,MUIA_Text_Contents,"Offline");

set(app->TX_LoadProgress,MUIA_Text_Contents,"Open Main Window");

set(app->WI_Main,MUIA_Window_Open,TRUE);

get(app->WI_Main,MUIA_Window_Window,&mywin);
if (mywin) {
  pr = (struct Process *)FindTask(NULL);
  oldwinptr = pr->pr_WindowPtr;
  pr->pr_WindowPtr = mywin;
  SetTaskPri((struct Task *)pr,1);
}

get(app->CY_MyStatus,MUIA_Cycle_Active,&index);
if (Codes[index] != STATUS_OFFLINE) ConnectICQ(NULL);

get(app->CH_OpenLog,MUIA_Selected,&auto_ch);
if (auto_ch) set(app->WI_Log,MUIA_Window_Open,TRUE);

for(i = 0; i < NUM_AFFILIATIONS; i++) {
  get(app->OB_Affiliations[i][0],MUIA_Selected,&auto_ch);
  if (!BOOLP(auto_ch)) DoMethod(app->WI_ICQPrefs,MUIM_MultiSet,MUIA_Disabled,TRUE,app->OB_Affiliations[i][1],app->OB_Affiliations[i][2],NULL);
}

for(i = 0; i < NUM_PASTS; i++) {
  get(app->OB_Pasts[i][0],MUIA_Selected,&auto_ch);
  if (!BOOLP(auto_ch)) DoMethod(app->WI_ICQPrefs,MUIM_MultiSet,MUIA_Disabled,TRUE,app->OB_Pasts[i][1],app->OB_Pasts[i][2],NULL);
}

for(i = 0; i < NUM_INTERESTS; i++) {
  get(app->OB_Interests[i][0],MUIA_Selected,&auto_ch);
  if (!BOOLP(auto_ch)) DoMethod(app->WI_ICQPrefs,MUIM_MultiSet,MUIA_Disabled,TRUE,app->OB_Interests[i][1],app->OB_Interests[i][2],NULL);
}

get(app->CH_PicPrivacy,MUIA_Selected,&auto_ch);
set(app->RD_PicPrivacies,MUIA_Disabled,BOOLP(auto_ch));

// set(app->WI_Progress,MUIA_Window_Open,FALSE);
set(app->WI_Splash,MUIA_Window_Open,FALSE);

get(app->STR_OnStartup,MUIA_String_Contents,&cmd);
if (strlen(cmd) > 0) System(cmd,NULL);

while(DoMethod(app->App,MUIM_Application_NewInput,&sigs) != MUIV_Application_ReturnID_Quit) {
  if (sigs) {
    sigs = Wait(sigs|SIGBREAKF_CTRL_C);
    if (sigs & SIGBREAKF_CTRL_C) break;
  }
}

get(app->STR_OnShutdown,MUIA_String_Contents,&cmd);
if (strlen(cmd) > 0) System(cmd,NULL);

DoMethod(app->LV_OfflineList,MUIM_NList_UseImage,NULL,-1,0);

get(app->LV_SockList,MUIA_NList_Entries,&total);

for(i = (total-1); i>-1; i--) {
  DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  CloseSocket(socks->Socket);
}

DoMethod(app->TX_Port  ,PORT_RemApp,app->App);
DoMethod(app->TX_Timer ,TIME_RemApp,app->App);
DoMethod(app->TX_Timer1,TIME_RemApp,app->App);
DoMethod(app->CC_Parse ,TIME_RemApp,app->App);

SavePrefs(NULL);

if (mywin) pr->pr_WindowPtr = oldwinptr;

set(app->WI_Main,MUIA_Window_Open,FALSE);

fail(NULL,NULL);

}


void fail(struct ObjApp *garbage, char *str)

{

if (app) {
  if (app->DO_IconifyIcon) FreeDiskObject(app->DO_IconifyIcon);
  if (app->NM_MsgMenu) MUI_DisposeObject(app->NM_MsgMenu);
  if (app->TX_Port) MUI_DisposeObject(app->TX_Port);
  if (app->TX_Timer) MUI_DisposeObject(app->TX_Timer);
  if (app->TX_Timer1) MUI_DisposeObject(app->TX_Timer1);
  if (app->CC_Parse) MUI_DisposeObject(app->CC_Parse);
  if (app->App) MUI_DisposeObject(app->App);
  if (mcc_Port) MUI_DeleteCustomClass(mcc_Port);
  if (mcc_Time) MUI_DeleteCustomClass(mcc_Time);
  if (mcc_Color) MUI_DeleteCustomClass(mcc_Color);
  if (mcc_Chat) MUI_DeleteCustomClass(mcc_Chat);
  FreeVec(app);
}

if (OpenURLBase)   CloseLibrary(OpenURLBase);
if (SocketBase)    CloseLibrary(SocketBase);
if (AsyncIOBase)   CloseLibrary(AsyncIOBase);
if (MUIMasterBase) CloseLibrary(MUIMasterBase);

if (str) {
  puts(str);
  exit(20);
}

exit(0);

}


APTR __asm AddOffline(REG(a2) APTR pool, REG(a1) struct Contact *user)

{

struct Contact *newuser = NULL;

if (!(newuser = AllocVec(sizeof(struct Contact),MEMF_CLEAR))) return(NULL);

newuser->UIN = user->UIN;

RefreshUInfo(&newuser->Nick,user->Nick);
RefreshUInfo(&newuser->First,user->First);
RefreshUInfo(&newuser->Last,user->Last);
RefreshUInfo(&newuser->EMail,user->EMail);
RefreshUInfo(&newuser->EMail_Secondary,user->EMail_Secondary);
RefreshUInfo(&newuser->EMail_Old,user->EMail_Old);
RefreshUInfo(&newuser->Street,user->Street);
RefreshUInfo(&newuser->City,user->City);
RefreshUInfo(&newuser->State,user->State);
RefreshUInfo(&newuser->ZipCode,user->ZipCode);
RefreshUInfo(&newuser->Phone,user->Phone);
RefreshUInfo(&newuser->FAX,user->FAX);
RefreshUInfo(&newuser->Cellular,user->Cellular);
RefreshUInfo(&newuser->HomePage,user->HomePage);
RefreshUInfo(&newuser->About,user->About);
RefreshUInfo(&newuser->Comment,user->Comment);

strcpy(newuser->LampTxt,user->LampTxt);

newuser->LampObj = user->LampObj;
newuser->LampNum = user->LampNum;
newuser->Occupation = user->Occupation;
newuser->Country = user->Country;
newuser->TimeZone = user->TimeZone;
newuser->Age = user->Age;
newuser->Sex = user->Sex;
newuser->BDay_Year = user->BDay_Year;
newuser->BDay_Month = user->BDay_Month;
newuser->BDay_Day = user->BDay_Day;
newuser->Language1 = user->Language1;
newuser->Language2 = user->Language2;
newuser->Language3 = user->Language3;
newuser->Authorize = user->Authorize;
newuser->IP = user->IP;
newuser->Port = user->Port;
newuser->RealIP = user->RealIP;
newuser->Type = user->Type;
newuser->CanTCP = user->CanTCP;
newuser->Status = user->Status;
newuser->SeeInvis = user->SeeInvis;
newuser->BeInvis = user->BeInvis;
newuser->EditEMail = user->EditEMail;
newuser->NewMsg = user->NewMsg;
newuser->UWin = user->UWin;
newuser->CFWin = user->CFWin;
newuser->FWin = user->FWin;
newuser->Changed = user->Changed;
newuser->ConnectMe = user->ConnectMe;
newuser->ChatListen = user->ChatListen;
newuser->LastOnline = user->LastOnline;
newuser->LastMessageFm = user->LastMessageFm;
newuser->LastMessageTo = user->LastMessageTo;

return(newuser);

}


void __asm RemOffline(REG(a2) APTR pool, REG(a1) struct Contact *newuser)

{

FreeUser(newuser);

if (newuser->LampObj) {
  DoMethod(app->LV_OfflineList,MUIM_NList_UseImage,NULL,newuser->LampNum,0L);
  MUI_DisposeObject(newuser->LampObj);
}

if (newuser->UWin) {
  if (!newuser->UWin->DoNotDelete) {
    if (newuser->UWin->WI_UserWindow) {
      set(newuser->UWin->WI_UserWindow,MUIA_Window_Open,FALSE);
      DoMethod(app->App,OM_REMMEMBER,newuser->UWin->WI_UserWindow);
      MUI_DisposeObject(newuser->UWin->WI_UserWindow);
    }
    FreeVec(newuser->UWin);
  }
  else newuser->UWin->DoNotDelete = FALSE;
}

if (newuser->CFWin) {
  if (newuser->CFWin->WI_ChatFileInWin) {
    set(newuser->CFWin->WI_ChatFileInWin,MUIA_Window_Open,FALSE);
    DoMethod(app->App,OM_REMMEMBER,newuser->CFWin->WI_ChatFileInWin);
    MUI_DisposeObject(newuser->CFWin->WI_ChatFileInWin);
  }
  FreeVec(newuser->CFWin);
}

if (newuser->FWin) {
  if (!newuser->FWin->DoNotDelete) {
    if (newuser->FWin->WI_FileWin) {
      set(newuser->FWin->WI_FileWin,MUIA_Window_Open,FALSE);
      DoMethod(app->App,OM_REMMEMBER,newuser->FWin->WI_FileWin);
      MUI_DisposeObject(newuser->FWin->WI_FileWin);
    }
    if (newuser->FWin->File) CloseAsync(newuser->FWin->File);
    FreeVec(newuser->FWin);
  }
  else newuser->FWin->DoNotDelete = FALSE;
}

FreeVec(newuser);

return;

}


LONG __asm CmpOffline(REG(a1) struct Contact *u1, REG(a2) struct Contact *u2)

{

ULONG s1, s2;

s1 = u1->Status & 0x000000ff;
s2 = u2->Status & 0x000000ff;

if (s1 < s2) return(-1);
if (s1 > s2) return(1);

if (u1->NewMsg < u2->NewMsg) return(1);
if (u1->NewMsg > u2->NewMsg) return(-1);

return(stricmp(u1->Nick,u2->Nick));

}


void __asm DisplayOffline(REG(a2) char **array, REG(a1) struct Contact *user)

{

static char uin[50], nick[100], name[100], email[100], auth[20], status[30], ip[30], port[20], cinvis[10];

ULONG pen = 2;

struct ColorText *ct;

name[0] = '\0';

if (user) {
  ct = GetStatus(user->Status);
  pen = MUIPEN(ct->Pen);
  sprintf(status,"\033P[%ld]%s",pen,ct->Status);
  sprintf(uin,"\033P[%ld]%ld",pen,user->UIN);
  if (user->Nick) sprintf(nick,"\033P[%ld]%s",pen,user->Nick);
  else strcpy(nick," ");
  if (user->First && user->Last) sprintf(name,"\033P[%ld]%s %s",pen,user->First,user->Last);
  else {
    if (user->First) sprintf(name,"\033P[%ld]%s",pen,user->First);
    if (user->Last) sprintf(name,"\033P[%ld]%s",pen,user->Last);
  }
  if (user->EMail) sprintf(email,"\033P[%ld]%s",pen,user->EMail);
  else strcpy(email," ");
  if (user->Authorize) sprintf(auth,"\033P[%ld]No",pen);
  else sprintf(auth,"\033P[%ld]Yes",pen);
  if (user->Status & STATUSF_HIDEIP) sprintf(ip,"\033P[%ld]Hidden",pen);
  else sprintf(ip,"\033P[%ld]%s",pen,Inet_NtoA(user->IP));
  if (user->Status & STATUSF_HIDEIP) sprintf(port,"\033P[%ld]Hidden",pen);
  else sprintf(port,"\033P[%ld]%ld",pen,user->Port);
  if (user->SeeInvis) sprintf(cinvis,"\033P[%ld]Yes",pen);
  else sprintf(cinvis,"\033P[%ld]No",pen);
  *array++ = user->LampTxt;
  *array++ = uin;
  *array++ = status;
  *array++ = nick;
  *array++ = name;
  *array++ = email;
  *array++ = auth;
  *array++ = cinvis;
  *array++ = ip;
  *array   = port;
}
else {
  *array++ = " ";
  *array++ = "User ID";
  *array++ = "Status";
  *array++ = "Nick";
  *array++ = "Name";
  *array++ = "EMail";
  *array++ = "Auth.";
  *array++ = "See Invis";
  *array++ = "IP";
  *array   = "Port";
}

return;

}


void FreeUser(struct Contact *newuser)

{

if (newuser->Nick) FreeVec(newuser->Nick);
if (newuser->First) FreeVec(newuser->First);
if (newuser->Last) FreeVec(newuser->Last);
if (newuser->EMail) FreeVec(newuser->EMail);
if (newuser->EMail_Secondary) FreeVec(newuser->EMail_Secondary);
if (newuser->EMail_Old) FreeVec(newuser->EMail_Old);
if (newuser->Street) FreeVec(newuser->Street);
if (newuser->City) FreeVec(newuser->City);
if (newuser->State) FreeVec(newuser->State);
if (newuser->ZipCode) FreeVec(newuser->ZipCode);
if (newuser->Phone) FreeVec(newuser->Phone);
if (newuser->FAX) FreeVec(newuser->FAX);
if (newuser->Cellular) FreeVec(newuser->Cellular);
if (newuser->HomePage) FreeVec(newuser->HomePage);
if (newuser->About) FreeVec(newuser->About);
if (newuser->Comment) FreeVec(newuser->Comment);
if (newuser->Work_City) FreeVec(newuser->Work_City);
if (newuser->Work_State) FreeVec(newuser->Work_State);
if (newuser->Work_Phone) FreeVec(newuser->Work_Phone);
if (newuser->Work_FAX) FreeVec(newuser->Work_FAX);
if (newuser->Work_Address) FreeVec(newuser->Work_Address);
if (newuser->Work_ZipCode) FreeVec(newuser->Work_ZipCode);
if (newuser->Work_Company) FreeVec(newuser->Work_Company);
if (newuser->Work_Department) FreeVec(newuser->Work_Department);
if (newuser->Work_Position) FreeVec(newuser->Work_Position);
if (newuser->Work_URL) FreeVec(newuser->Work_URL);

return;

}


ULONG __asm MyDispatcher(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg)

{

switch(msg->MethodID) {
  case OM_NEW:
    return(PORT_NewUDP(cl,obj,(APTR)msg));
  case OM_DISPOSE:
    return(PORT_Dispose(cl,obj,(APTR)msg));
  case PORT_AddApp:
    return(PORT_Setup(cl,obj,(APTR)msg));
  case PORT_RemApp:
    return(PORT_Cleanup(cl,obj,(APTR)msg));
  case PORT_Trigger:
    return(PORT_Trigger_cl(cl,obj,(APTR)msg));
}

return(DoSuperMethodA(cl,obj,msg));

}


ULONG PORT_NewUDP(struct IClass *cl, Object *obj, Msg msg)

{

struct SigData *data;

#ifdef DEBUG
HandleError(DBG_OTH_INFO,"In PORT_NewUDP");
#endif

if (!(obj = (Object *)DoSuperMethodA(cl,obj,msg))) return(FALSE);

data = INST_DATA(cl,obj);

if ((PORT_signal = AllocSignal(-1)) == -1) {
  HandleError(DBG_OTH_INFO,"No signal bit allocated.");
  CoerceMethod(cl,obj,OM_DISPOSE);
  return(FALSE);
}

PORT_mask = 1L<<PORT_signal;

if (PORT_mask) {
  data->ihnode.ihn_Object  = obj;
  data->ihnode.ihn_Signals = PORT_mask;
  data->ihnode.ihn_Method  = PORT_Trigger;
  data->ihnode.ihn_Flags   = 0;
  return((ULONG)obj);
}


CoerceMethod(cl,obj,OM_DISPOSE);

return(FALSE);

}


ULONG PORT_Dispose(struct IClass *cl, Object *obj, Msg msg)

{

#ifdef DEBUG
HandleError(DBG_OTH_INFO,"In PORT_Dispose");
#endif

if (PORT_signal > -1) FreeSignal(PORT_signal);

return(DoSuperMethodA(cl,obj,msg));

}


ULONG PORT_Setup(struct IClass *cl, Object *obj, Msg msg)

{

struct SigData *data = INST_DATA(cl,obj);

#ifdef DEBUG
HandleError(DBG_OTH_INFO,"In PORT_Setup");
#endif

data->App = ((struct MUIP_PT_AddApp *)msg)->App;

DoMethod(data->App,MUIM_Application_AddInputHandler,&data->ihnode);

return(TRUE);

}


ULONG PORT_Cleanup(struct IClass *cl, Object *obj, Msg msg)

{

struct SigData *data = INST_DATA(cl,obj);

#ifdef DEBUG
HandleError(DBG_OTH_INFO,"In PORT_Cleanup");
#endif

DoMethod(data->App,MUIM_Application_RemInputHandler,&data->ihnode);

return(DoSuperMethodA(cl,obj,msg));

}


ULONG PORT_Trigger_cl(struct IClass *cl, Object *obj, Msg msg)

{

BOOL flag = FALSE, flg2 = FALSE;

fd_set rs, ws;

int data_len, len = 0, acklen = 0, i;

LONG s, total, user_len, n, size;

UWORD ver, cmd, seq;

ULONG err;

struct Contact *user;
struct ICQLog *Logged = NULL;
struct Sockets Socks, *socks;
struct timeval tv;
struct UDP_Header ACKHeader;

//struct SigData *data = INST_DATA(cl,obj);

if (maxfd < 0 || !SocketBase) return(flag);

ver = cmd = seq = 0;

/*
printf("rset: ");

for(i = 0; i<(maxfd+1); i++) if (FD_ISSET(i,&rset)) printf("%d ",i);

printf("\nwset: ");

for(i = 0; i<(maxfd+1); i++) if (FD_ISSET(i,&wset)) printf("%d ",i);

printf("\n");
*/

rs = rset;
ws = wset;

tv.tv_sec = 0;
tv.tv_usec = 0;

//printf("maxfd = %d\n",maxfd);

if ((n = WaitSelect(maxfd+1,&rs,&ws,NULL,&tv,NULL)) == 0) return(flag);

#ifdef DEBUG
HandleError(DBG_OTH_INFO,"In PORT_Trigger");
#endif

for(s = 0; s<(maxfd+1); s++) {
  if (!FD_ISSET(s,&rs) && !FD_ISSET(s,&ws)) continue;
  socks = GetSocketFmSocket(s);
  if (socks) {
    if ((socks->Type == SOCK_UDP) && FD_ISSET(s,&rs)) {
      n = sizeof(err);
      if (getsockopt(s,SOL_SOCKET,SO_ERROR,&err,&n) < 0 || err != 0) {
        switch(err) {
          case ECONNRESET:
          case ECONNREFUSED:
          case EHOSTUNREACH:
          case ETIMEDOUT:
            break;
          default:
            SocketBaseTags(SBTM_GETREF(SBTC_ERRNOSTRPTR),&err,TAG_DONE);
            HandleError(DBG_UDP_ERRS,"Error on UDP socket: %s",(char *)err);
        }
        DisconnectICQ(NULL);
        continue;
      }
      flag = TRUE;
      while((data_len = recv_udp_pkt(rbuf,sizeof(rbuf),socks)) > 0) {
        len = 0;
        UDP_ParseHeader(rbuf,&Header);
        sprintf(err_buf,"Incoming %s packet",ICQ_CmdToText(Header.Command));
        PrintHex(DBG_UDP_PKTS,err_buf,rbuf,data_len);
        if (Header.Version == 2 || Header.Version == 5) {
//        HandleError(DBG_UDP_DBUG," ver = %d",Header.Version);
//        HandleError(DBG_UDP_DBUG," cmd = 0x%04x",Header.Command);
//        HandleError(DBG_UDP_DBUG," seq = %d",Header.Sequence);
//        HandleError(DBG_UDP_DBUG," se2 = %d",Header.Sequence2);
          if (Header.Command != S_ACK) {
            memcpy(&ACKHeader,&Header,sizeof(struct UDP_Header));
            ACKHeader.Command = C_ACK;
            acklen = UDP_CreatePacket(&ACKHeader,NULL,UDP_Buf);
            send_udp_pkt(UDP_Buf,acklen,socks->UIN);
            if (Header.Command == S_NEW_USER_UIN) Header.Sequence = 0xffff;
            get(app->LV_ICQSrvLog,MUIA_NList_Entries,&total);
            for(i = total-1; i>-1; i--) {
              DoMethod(app->LV_ICQSrvLog,MUIM_NList_GetEntry,i,&Logged);
              if (Logged) {
                switch(Header.Version) {
                  case 0x0002:
                    if (Logged->Seq == Header.Sequence) {
                      Logged->Resend++;
                      flg2 = TRUE;
                    }
                    break;
                  case 0x0005:
//                  HandleError(DBG_UDP_DBUG,"Data Logged->Seq = %04lx, Header.Sequence = %04x, Logged->Se2 = %04x, Header.Sequence2 = %04x",Logged->Seq,Header.Sequence,Logged->Se2,Header.Sequence2);
                    if (Logged->Seq == Header.Sequence && Logged->Se2 == Header.Sequence2) {
                      Logged->Resend++;
                      flg2 = TRUE;
                    }
                    break;
                }
                if (flg2) break;
              }
            }
            if (!flg2) {
              if (Header.Command == S_MULTI) {
                struct S_Multi Multi;
                struct UDP_Header MHdr;
                UDP_ParseHeader(rbuf,&MHdr);
                UDP_ParsePacket(&Multi,rbuf,data_len,&MHdr);
                while(Multi.Size && Multi.Packet) {
                  UDP_ParseHeader(Multi.Packet,&MHdr);
                  sprintf(err_buf,"MultiPacket contains a %s packet (%d remain)",ICQ_CmdToText(MHdr.Command),Multi.Count-1);
                  PrintHex(DBG_UDP_PKTS,err_buf,Multi.Packet,Multi.Size);
                  if (MHdr.Command == S_ACK) HandleACK(Multi.Packet,Multi.Size);
                  else Add2Log(LOG_SERVER,&MHdr,TRUE,Multi.Size,Multi.Packet);
                  UDP_NextMulti(&Multi);
                }
              }
              else Add2Log(LOG_SERVER,&Header,TRUE,data_len,rbuf);
            }
          }
          else HandleACK(rbuf,data_len);
        }
        else PrintHex(DBG_UDP_ERRS,"Bad UDP version, its not v2 or v5",rbuf,data_len);
      }
      continue;
    }
  }
  if (socks) {
    if (socks->Type == SOCK_UDP) continue;
    if ((socks->Dir == TCP_DIR_LISTEN) && FD_ISSET(s,&rs)) {
      HandleError(DBG_TCP_DBUG,"incoming connection request on socket %d",s);
      user_len = sizeof(Socks.Address);
      if ((Socks.Socket = accept(s,(struct sockaddr *)&Socks.Address,&user_len)) < 0) HandleError(DBG_OTH_INFO,"Error return from accept().");
      else {
        HandleError(DBG_TCP_DBUG,"New socket is %d",Socks.Socket);
        Socks.UIN = 0;
        Socks.Dir = TCP_DIR_IN;
        Socks.TCPLen = 0;
        Socks.LastTCP = NULL;
        Socks.ChatMode = Socks.FileMode = NULL;
        Socks.CWin = NULL;
        Socks.RCObj = NULL;
        Socks.Timehack = time(NULL);
        Socks.Connecting = Socks.HadInit = Socks.Hidden = Socks.Backward = Socks.Closing = FALSE;
        Socks.Type = socks->Type;
        Socks.PktLen[0] = Socks.PktLen[1] = '\0';
        Socks.ConnectPort = socks->Port;
        Socks.CWin = NULL;
        if (Socks.Socket > maxfd) maxfd = Socks.Socket;
        FD_SET(Socks.Socket,&rset);
        FD_SET(Socks.Socket,&wset);
        tv.tv_sec = 30;
        tv.tv_usec = 0;
        size = 1;
        memset(&Socks.Address,0,user_len);
        if (IoctlSocket(Socks.Socket,FIOASYNC,(char *)&size) == -1) {
          HandleError(DBG_TCP_ERRS,"Error in IoctlSocket FIOASYNC for incoming TCP socket.");
        }
        if (IoctlSocket(Socks.Socket,FIONBIO,(char *)&size) == -1) {
          HandleError(DBG_TCP_ERRS,"Error in IoctlSocket FIONBIO for incoming TCP socket.");
        }
        if (setsockopt(Socks.Socket,SOL_SOCKET,SO_SNDTIMEO,&tv,sizeof(tv)) == -1) {
          HandleError(DBG_TCP_ERRS,"Could not setsockopt SO_SNDTIMEO for incoming TCP socket.");
        }
        size = FILE_PKT_SIZE*2;
        if (setsockopt(Socks.Socket,SOL_SOCKET,SO_SNDLOWAT,&size,sizeof(size)) == -1) {
          HandleError(DBG_TCP_ERRS,"Could not setsockopt SO_SNDLOWAT for incoming TCP socket.");
        }
        getpeername(Socks.Socket,(struct sockaddr *)&Socks.Address,&user_len);
        Socks.IP = Socks.Address.sin_addr.s_addr;
        Socks.Port = Socks.Address.sin_port;
        memset(&Socks.LocalAddr,0,user_len);
        getsockname(Socks.Socket,(struct sockaddr *)&Socks.LocalAddr,&user_len);
        DoMethod(app->LV_SockList,MUIM_NList_InsertSingle,&Socks,MUIV_NList_Insert_Sorted);
      }
      continue;
    }
  }
  if (socks) user = GetContact(socks->UIN);
  if (socks) {
    if (socks->Connecting && (FD_ISSET(s,&rs) || FD_ISSET(s,&ws))) {
      n = sizeof(err);
      if (getsockopt(s,SOL_SOCKET,SO_ERROR,&err,&n) < 0 || err != 0) {
        switch(err) {
          case ECONNRESET:
          case ECONNREFUSED:
          case EHOSTUNREACH:
          case ETIMEDOUT:
            break;
          default:
            SocketBaseTags(SBTM_GETREF(SBTC_ERRNOSTRPTR),&err,TAG_DONE);
            HandleError(DBG_TCP_ERRS,"non-blocking connect for %s failed: %s.",user->Nick,(char *)err);
        }
        if (socks->IP != user->RealIP && user->RealIP != 0) {
          HandleError(DBG_TCP_DBUG,"Attempting RealIP.");
          if (!OpenTCPSocket(user,socks->Type,user->RealIP,socks->Port)) {
            user->CanTCP = 6;
            user->IP = user->Port = 0;
            if (socks->Type == SOCK_CHAT && user->ChatListen) DelSockets(user->ChatListen);
//          if (socks->Type == SOCK_FILE && user->FileListen) DelSockets(user->FileListen);
            user->ChatListen = /* user->FileListen = */ 0;
            DelSockets(s);
            if (s == maxfd) maxfd--;
            continue;
          }
        }
        else {
          user->CanTCP = 6;
          user->IP = user->Port = 0;
          if (socks->Type == SOCK_CHAT && user->ChatListen) DelSockets(user->ChatListen);
//        if (socks->Type == SOCK_FILE && user->FileListen) DelSockets(user->FileListen);
          user->ChatListen = /* user->FileListen = */ 0;
          DelSockets(s);
          if (s == maxfd) maxfd--;
          SendTCPMsgViaUDP(user->UIN);
          continue;
        }
        DelSockets(s);
        if (s == maxfd) maxfd--;
        continue;
      }
      HandleError(DBG_TCP_DBUG,"completed connection on %s's socket %d",user->Nick,s);
      socks->Connecting = FALSE;
      user_len = sizeof(socks->Address);
      if (getpeername(s,(struct sockaddr *)&socks->Address,&user_len) == -1) {
        HandleError(DBG_TCP_ERRS,"Error in getpeername for non-blocking TCP connect.");
        continue;
      }
      socks->IP = socks->Address.sin_addr.s_addr;
      socks->Port = socks->Address.sin_port;
      if (user->Status & STATUSF_HIDEIP) socks->Hidden = TRUE;
      user_len = sizeof(socks->LocalAddr);
      memset(&socks->LocalAddr,0,user_len);
      getsockname(socks->Socket,(struct sockaddr *)&socks->LocalAddr,&user_len);
      user->Type = TCP_MSG_MSG;
      switch(socks->Type) {
        case SOCK_MESSAGE:
          SendTCPInit(s,user,0);
          SendDelayedTCP(socks);
          break;
        case SOCK_CHAT:
          SendTCPInit(s,user,user->ChatListen);
          if (!socks->Backward) SendChatInit(s);
          break;
        case SOCK_FILE:
          SendTCPInit(s,user,FileListen);
          if (!socks->Backward) SendFileInit(s,user);
          break;
      }
      continue;
    }
  }
/*if (FD_ISSET(s,&ws)) {
    if (socks) {
      if (socks->Type == SOCK_FILE && socks->FileMode) {
//      HandleError(DBG_TCP_DBUG,"%s's FileDirect socket %d is writeable.",user->Nick,s);
        n = sizeof(err);
        if (getsockopt(s,SOL_SOCKET,SO_ERROR,&err,&n) < 0 || err != 0) {
          switch(err) {
            case ECONNRESET:
            case ECONNREFUSED:
            case EHOSTUNREACH:
            case ETIMEDOUT:
              break;
            default:
              SocketBaseTags(SBTM_GETREF(SBTC_ERRNOSTRPTR),&err,TAG_DONE);
              HandleError(DBG_TCP_ERRS,"Error on writeable TCP socket:  %s",(char *)err);
          }
          user->CanTCP = 6;
          user->IP = user->Port = 0;
          if (socks->Type == SOCK_FILE) EndFile(user);
          DelSockets(s);
          if (s == maxfd) maxfd--;
          continue;
        }
//      SendAFile(s,user);
      }
    }
  }  */
  if (FD_ISSET(s,&rs)) {
    if (socks) {
//    HandleError(DBG_TCP_DBUG,"incoming data on socket %d",s);
      n = sizeof(err);
      if (getsockopt(s,SOL_SOCKET,SO_ERROR,&err,&n) < 0 || err != 0) {
        switch(err) {
          case ECONNRESET:
          case ECONNREFUSED:
          case EHOSTUNREACH:
          case ETIMEDOUT:
            break;
          default:
            SocketBaseTags(SBTM_GETREF(SBTC_ERRNOSTRPTR),&err,TAG_DONE);
            HandleError(DBG_TCP_ERRS,"Error on readable TCP socket:  %s",(char *)err);
        }
        if (user) {
          user->CanTCP = 6;
          user->IP = user->Port = 0;
          if (socks->Type == SOCK_CHAT) EndChat(socks->RCObj->GP_RemoteObj);
          if (socks->Type == SOCK_FILE) EndFile(user);
        }
        DelSockets(s);
        if (s == maxfd) maxfd--;
        continue;
      }
      while ((socks->ChatMode?(len = recv_chat(tbuf,s)):(len = recv_tcp_pkt(tbuf,socks))) > 0) {
        switch(socks->Type) {
          case SOCK_MESSAGE:
            ParseTCPCmd(tbuf,len,s);
            break;
          case SOCK_CHAT:
            if (socks->ChatMode) DoChatMode(tbuf,len,s);
            else ParseChatPkt(tbuf,len,s);
            break;
          case SOCK_FILE:
            ParseFilePkt(tbuf,len,s);
            break;
        }
      }
      if (len < 0) {
        switch(socks->Type) {
          case SOCK_CHAT:
            if (socks->RCObj) EndChat(socks->RCObj->GP_RemoteObj);
            break;
          case SOCK_FILE:
            if (user) EndFile(user);
            break;
          default:
            DelSockets(s);
        }
        if (s == maxfd) maxfd--;
      }
    }
  }
}

return(flag);

}


void HandleACK(char *rbuf, UWORD data_len)

{

int i;

ULONG total;

struct ICQLog *Logged;

if (NewUser) {
  Add2Log(LOG_SERVER,&Header,TRUE,data_len,rbuf);
}
get(app->LV_ICQCliLog,MUIA_NList_Entries,&total);
for(i = total-1; i>-1; i--) {
  DoMethod(app->LV_ICQCliLog,MUIM_NList_GetEntry,i,&Logged);
  if (Logged) {
    switch(Header.Version) {
      case 0x0002:
        if (Logged->Seq == Header.Sequence) Logged->Ack = TRUE;
        break;
      case 0x0005:
//      HandleError(DBG_UDP_DBUG,"ACK Logged->Seq = %04lx, Header.Sequence = %04x, Logged->Se2 = %04x, Header.Sequence2 = %04x",Logged->Seq,Header.Sequence,Logged->Se2,Header.Sequence2);
        if (Logged->Seq == Header.Sequence && Logged->Se2 == Header.Sequence2) Logged->Ack = TRUE;
        break;
    }
    if (Logged->Ack && Logged->Len) {
      Logged->Len = 0;
      FreeVec(Logged->Pkt);
      Logged->Pkt = NULL;
      DoMethod(app->LV_ICQCliLog,MUIM_NList_Redraw,i);
      break;
    }
  }
}

return;

}


void __asm ConnectICQ(REG(a2) APTR obj)

{

BOOL *opts;

char *pass;

int i, len;

ULONG port, addr, stat, uin, index, total, udp_ver;

struct C_LogOn LogOn;
struct Sockets *socks;

if (Online) return;

if (!(SocketOpen = OpenICQSocket())) {
  HandleError(DBG_OTH_FATL,"Could not connect to ICQ.");
  return;
}

get(app->STR_ICQUIN ,MUIA_String_Integer ,&uin);
get(app->STR_ICQPass,MUIA_String_Contents,&pass);
get(app->CY_MyStatus,MUIA_Cycle_Active   ,&index);
get(app->LV_SockList,MUIA_NList_Entries  ,&total);
get(app->CY_UDPVersion,MUIA_Cycle_Active ,&udp_ver);

for(i = 0; i<total; i++) {
  DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  if (socks) if (socks->Type == SOCK_MESSAGE && socks->Dir == TCP_DIR_LISTEN && socks->UIN == uin) break;
}

port = socks->Port;
addr = socks->IP;
stat = Codes[index];

get(app->CH_WebPresence,MUIA_Selected,&opts);

if (opts) stat |= STATUSF_WEBPRESENCE;

get(app->CH_HideIP,MUIA_Selected,&opts);

if (opts) stat |= STATUSF_HIDEIP;

//HandleError(DBG_TCP_DBUG,"Status is 0x%08x",stat);

switch(udp_ver) {
  case 0:
    Header.Version = 0x0002;
    Header.Sequence2 = 0x0000;
    set(app->BT_ChangePW,MUIA_Disabled,TRUE);
    break;
  case 1:
    Header.Version = 0x0005;
    set(app->BT_ChangePW,MUIA_Disabled,FALSE);
    break;
}

Header.Command = C_LOGIN;

LogOn.Time = time(NULL);
LogOn.TCP_MsgPort = port;
strcpy(LogOn.Password,pass);
LogOn.TCP_MsgIP = addr;
LogOn.TCP_Flag = 0x04;
LogOn.Status = stat;
LogOn.Seq_Login = login_seq;

switch(Header.Version) {
  case 0x0002:
    LogOn.X1 = 0x00000000;
    LogOn.X3 = 0x00000002;
    LogOn.X4 = 0x00000000;
    LogOn.X5 = 0x007300D9;
    break;
  case 0x0005:
    LogOn.X1 = 0x000000D6;
    LogOn.X3 = 0x00000002; // TCP Version (Should be v6, but...)
    LogOn.X4 = 0x00000000;
    LogOn.X5 = 0x00D60000; // This changes
    LogOn.X6 = 0x00000050;
    LogOn.X7 = 0x00000003;
    LogOn.X8 = rand() & 0x3FFFFFFF;
    break;
}

len = UDP_CreatePacket(&Header,&LogOn,UDP_Buf);

if (FirstLogin) login_seq += 8;
else login_seq += 6;

if (send_udp_pkt(UDP_Buf,len,uin) < len) return;

TryAgain = FALSE;

if (!NewUser && !Reconnecting) {
  DoMethod(app->LV_ICQCliLog,MUIM_NList_Clear);
  DoMethod(app->LV_ICQSrvLog,MUIM_NList_Clear);
}

if (!Reconnecting) set(app->TX_Color,MUIA_Text_Contents,"Logging in...");
else Reconnecting = FALSE;

Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);

return;

}


void __asm DisconnectICQ(REG(a2) APTR obj)

{

int len = 0;

ULONG uin;

struct C_LogOff LogOff;

if (!Online) return;

//HandleError(DBG_UDP_DBUG,"DisconnectICQ()");

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);

Header.Command = C_SEND_TEXT_CODE;

LogOff.Text = "B_USER_DISCONNECTED";
LogOff.X1 = 0x0005;

len = UDP_CreatePacket(&Header,&LogOff,UDP_Buf);

send_udp_pkt(UDP_Buf,len,uin);

Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);

Online = FALSE;

if (obj == NULL) set(app->CY_MyStatus,MUIA_Cycle_Active,NUM_STATUS);

ContactsOffline();

LastSend = 0;

return;

}


int send_udp_pkt(void *packet, int length, ULONG uin)

{

BOOL *reconnect = NULL;

char *pkt;

int i, sent;

LONG total;

struct Sockets *socks;

get(app->LV_SockList,MUIA_NList_Entries,&total);

for(i = 0; i<total; i++) {
  DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  if (socks) if (socks->Type == SOCK_UDP && socks->UIN == uin) break;
}

switch(Header.Version) {
  case 0x0002:
    pkt = packet;
    sprintf(err_buf,"Outgoing %s packet",ICQ_CmdToText(Header.Command));
    break;
  case 0x0005:
    sprintf(err_buf,"Outgoing unencrypted %s packet",ICQ_CmdToText(Header.Command));
    PrintHex(DBG_UDP_PKTS,err_buf,packet,length);
    if (!(pkt = AllocVec(length+3,MEMF_CLEAR))) {
      HandleError(DBG_UDP_ERRS,"send_udp_pkt() - Could not allocate %d bytes!",length);
      return(0);
    }
    if (!UDP_EncryptPacket(pkt,packet,length)) return(0);
    sprintf(err_buf,"Outgoing encrypted %s packet",ICQ_CmdToText(Header.Command));
    break;
}

PrintHex(DBG_UDP_PKTS,err_buf,pkt,length);

sent = sendto(socks->Socket,pkt,length,0,(struct sockaddr *)&socks->Address,sizeof(socks->Address));

switch(Header.Version) {
  case 0x0005:
    FreeVec(pkt);
    break;
}

if (sent < length && !TryAgain) {
  HandleError(DBG_OTH_INFO,"Return from sendto (%d) less than length (%d).",sent,length);
  Online = FALSE;
  ContactsOffline();
  get(app->CH_Reconnect,MUIA_Selected,&reconnect);
  set(app->CY_MyStatus,MUIA_Cycle_Active,NUM_STATUS);
  if (reconnect) TryAgain = TRUE;
}

return(sent);

}


int recv_udp_pkt(void *packet, int length, struct Sockets *socks)

{

int recvd;

LONG structlength = sizeof(socks->Address);

recvd = recvfrom(socks->Socket,packet,length,0,(struct sockaddr *)&socks->Address,&structlength);

if (recvd < 0 && Errno() != EWOULDBLOCK) { /*HandleError(DBG_OTH_INFO,"There was a recvfrom error.");*/ }

return(recvd);

}


void revmemcpy(char *mem, char *dat, int len)

{

int i, j;

for(i = 0, j = len-1; i<len; i++, j--) *(mem+j) = *(dat+i);

return;

}


APTR __asm AddLog(REG(a2) APTR pool, REG(a1) struct ICQLog *log)

{

struct ICQLog *newlog = NULL;

if (!(newlog = AllocPooled(pool,sizeof(struct ICQLog)))) return(NULL);

if (log->Pkt && log->Len > 0) {
  if (!(newlog->Pkt = AllocVec(log->Len,MEMF_CLEAR))) {
    FreePooled(pool,newlog,sizeof(struct ICQLog));
    return(NULL);
  }
  memcpy(newlog->Pkt,log->Pkt,log->Len);
}
else newlog->Pkt = NULL;

newlog->UIN = log->UIN;
newlog->Seq = log->Seq;
newlog->Se2 = log->Se2;
newlog->Cmd = log->Cmd;
newlog->Ack = log->Ack;
newlog->Len = log->Len;
newlog->Resend = log->Resend;
newlog->Timehack = log->Timehack;

return(newlog);

}


void __asm RemLog(REG(a2) APTR pool, REG(a1) struct ICQLog *newlog)

{

if (newlog->Pkt) FreeVec(newlog->Pkt);

FreePooled(pool,newlog,sizeof(struct ICQLog));

return;

}


LONG __asm CmpLog(REG(a1) struct ICQLog *l1, REG(a2) struct ICQLog *l2)

{

if (l1->Seq < l2->Seq) return(-1);
if (l1->Seq > l2->Seq) return(1);

return(0);

}


void __asm DisplayLog(REG(a2) char **array, REG(a1) struct ICQLog *log)

{

static char seq[30], *cmd, pkt[10], ack[10], resend[10];

if (log) {
  if (log->Se2) sprintf(seq,"%d/%ld",log->Se2,log->Seq);
  else sprintf(seq,"%ld",log->Seq);
  cmd = ICQ_CmdToText(log->Cmd);
  if (log->Pkt) strcpy(pkt,"Yes");
  else strcpy(pkt,"No");
  if (log->Ack) strcpy(ack,"Yes");
  else strcpy(ack,"No");
  sprintf(resend,"%d",log->Resend);
  *array++ = seq;
  *array++ = cmd;
  *array++ = pkt;
  *array++ = resend;
  *array   = ack;
}
else {
  *array++ = "Seq";
  *array++ = "Command";
  *array++ = "Packet";
  *array++ = "Resend";
  *array   = "ACK";
}

return;

}


ULONG ParseUDPCommands(struct IClass *cl, Object *obj, Msg msg)

{

int i;

static int last = 0;

ULONG total;

UWORD cmd;

struct ICQLog *log;
struct TimeData *data = INST_DATA(cl,obj);

if (CheckIO((struct IORequest *)data->req_hbeat)) {
//HandleError(DBG_UDP_DBUG,"In ParseUDPCommands.");
  WaitIO((struct IORequest *)data->req_hbeat);
  data->req_hbeat->tr_node.io_Command = TR_ADDREQUEST;
  data->req_hbeat->tr_time.tv_secs = data->Seconds;
  data->req_hbeat->tr_time.tv_micro = data->Micros;
  get(app->LV_ICQSrvLog,MUIA_NList_Entries,&total);
  if (total < last) last = 0;
  if (last < total) {
    for(i = last; i < total; i++) {
      DoMethod(app->LV_ICQSrvLog,MUIM_NList_GetEntry,i,&log);
      if (log) {
        if (log->Pkt) {
          cmd = log->Cmd;
          ParseCmd(log->Cmd,log->Seq,log->Pkt,log->Len);
          if (cmd == 0x00F0 || cmd == S_TOO_BUSY || cmd == S_GO_AWAY) break;
          FreeVec(log->Pkt);
          log->Pkt = NULL;
          log->Len = 0;
          DoMethod(app->LV_ICQSrvLog,MUIM_NList_Redraw,i);
          last = i;
          break;
        }
      }
    }
  }
  SendIO((struct IORequest *)data->req_hbeat);
  return(TRUE);
}

return(FALSE);

}


void ParseCmd(UWORD cmd, UWORD seq, char *buf, int data_len)

{

int len = 0;

ULONG localin;

struct UDP_Header PHdr;

get(app->STR_ICQUIN,MUIA_String_Integer,&localin);

UDP_ParseHeader(buf,&PHdr);

switch(cmd) {
/*
  case S_ACK: {
    char *pw;
    UBYTE X1 = 0;
    ULONG uin = 0;
    UWORD ack = 0;
    struct C_NewUser NewUIN;
    switch(seq) {
      case 0x0001:
        revmemcpy((char *)&ack,buf+len,2); len += 2;
        revmemcpy((char *)&uin,buf+len,4); len += 4;
        revmemcpy((char *)&X1,buf+len,1); len++;
        if (ack == 0x000a) {
          get(app->STR_ICQPass,MUIA_String_Contents,&pw);
          Header.Command = C_NEW_USER_REG;
          NewUIN.X1 = 0x000c;
          strcpy(NewUIN.Password,pw);
          NewUIN.Random = (UWORD)rand();
          NewUIN.Pad = 0x0000;
          switch(Header.Version) {
            case 0x0002:
              NewUIN.X2 = 0x00000073;
              break;
            case 0x0005:
              NewUIN.X2 = 0x000000A0;
              NewUIN.X3 = 0x00A00000;
              NewUIN.X4 = 0x00000000;
              break;
          }
          len = UDP_CreatePacket(&Header,&NewUIN,UDP_Buf);
          send_udp_pkt(UDP_Buf,len,uin);
          Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
        }
        break;
    }
    break;
  }
*/
  case S_LOGIN_REPLY: {
    static char mesg[20];
    ULONG uin = 0;
//  struct C_LogOn_2 LogOn2;
    struct S_Login_Reply Reply;
    set(app->TX_Color,MUIA_Text_Contents,"Connected...");
    get(app->STR_ICQUIN,MUIA_String_Integer,&uin);

    UDP_ParsePacket(&Reply,buf,data_len,&PHdr);

    set(app->TX_CurrentIP,MUIA_Text_Contents,Inet_NtoA(Reply.IP));

    Header.Command = C_LOGIN_1;
    len = UDP_CreatePacket(&Header,NULL,UDP_Buf);
    send_udp_pkt(UDP_Buf,len,uin);
    Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
/*
    if (FirstLogin && !NewUser) {
      struct C_SendURLMsg URLMsg;
      Header.Command = C_SEND_URL_MESSAGE;
      URLMsg.Index = URLMsg_cnt;
      len = UDP_CreatePacket(&Header,&URLMsg,UDP_Buf);
      send_udp_pkt(UDP_Buf,len,uin);
      Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
    }

    if (!NewUser) {
      struct C_LogOn_3 LogOn3;
      Header.Command = C_LOGIN_3;
      LogOn3.X1 = 0x00000000;
      len = UDP_CreatePacket(&Header,&LogOn3,UDP_Buf);
      send_udp_pkt(UDP_Buf,len,uin);
      Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
    }
*/
//  if (FirstLogin && !NewUser) {
//    struct C_ServerStat SrvrStat;
//    Header.Command = C_QUERY_STATUS;
//    SrvrStat.Index = SrvrMsg_cnt;
//    len = UDP_CreatePacket(&Header,&SrvrStat,UDP_Buf);
//    send_udp_pkt(UDP_Buf,len,uin);
//    Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
//  }
/*
    Header.Command = C_LOGIN_2;
    LogOn2.X1 = 0x00;
    len = UDP_CreatePacket(&Header,&LogOn2,UDP_Buf);
    send_udp_pkt(UDP_Buf,len,uin);
    Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
*/
    if (NewUser) SendUInfo1(NULL);

    SendContacts(uin,C_CONTACT_LIST);
    SendContacts(uin,C_VIS_LIST);
    SendContacts(uin,C_INVIS_LIST);

    if (NewUser) SendUInfo2(NULL);

    sprintf(mesg,"%s (%ld)",GetNick(uin),uin);
    set(app->TX_Color,MUIA_Text_Contents,mesg);
    Online = TRUE;
    FirstLogin = NewUser = FALSE;
    break;
  }
  case S_BAD_PASSWORD:
    set(app->TX_Color,MUIA_Text_Contents,"Bad Password");
    break;
  case S_RECEIVE_MESSAGE: {
    BOOL flag = TRUE;
    char tmp[80];
    struct Contact *user;
    struct ICQMessage msg;
    struct S_Receive_Message Offline;
    UDP_ParsePacket(&Offline,buf,data_len,&PHdr);
    if (CheckIgnore(Offline.UIN)) break;
    sprintf(tmp,"Message Sent %02d/%02d/%04d at %02d:%02d",Offline.Day,Offline.Month,Offline.Year,Offline.Hour,Offline.Minute);
    msg.Msg = tmp;
    msg.Timehack = time(NULL);
    msg.Type = Offline.Type;
    msg.UIN = Offline.UIN;
    DoMethod(app->LV_Msgs,MUIM_NList_InsertSingleWrap,&msg,MUIV_NList_Insert_Bottom,WRAPCOL2,ALIGN_LEFT);
    if (user = GetContact(Offline.UIN)) {
      if (!user->UWin) flag = CreateUserWin(Offline.UIN);
      if (flag) DoMethod(user->UWin->LV_Msgs,MUIM_NList_InsertSingleWrap,&msg,MUIV_NList_Insert_Bottom,WRAPCOL2,ALIGN_LEFT);
    }
    ParseMessage(PHdr.Command,Offline.MessageBuf,Offline.UIN,Offline.Type);
    break;
  }
  case S_GET_MESSAGE: {
    BOOL *useaway = NULL;
    char *awaymsg;
    LONG index;
    time_t temp;
    struct S_Get_Message Message;
    UDP_ParsePacket(&Message,buf,data_len,&PHdr);
    if (CheckIgnore(Message.UIN)) break;
    ParseMessage(PHdr.Command,Message.MessageBuf,Message.UIN,Message.Type);
    get(app->STR_ICQUIN,MUIA_String_Integer,&localin);
    get(app->CY_MyStatus,MUIA_Cycle_Active,&index);
    get(app->CH_UseMessages[index],MUIA_Selected,&useaway);
    if (useaway) {
      get(app->STR_Messages[index],MUIA_String_Contents,&awaymsg);
      if (strlen(awaymsg) && Message.UIN != localin) {
        temp = LastSend;
        SendAMessage(NULL,Message.UIN,awaymsg,0x0001,MSG_BOTH,MSG_VIA_BEST);
        LastSend = temp;
      }
    }
    if (!GetContact(Message.UIN) && Message.UIN != 10) set(app->WI_Message,MUIA_Window_Open,TRUE);
    break;
  }
  case S_STATUS_UPDATE : {
    int i;
    ULONG total = 0;
    struct ColorText *ct;
    struct Contact *user;
    struct Activity Acty;
    struct S_Status_Update Status;
    UDP_ParsePacket(&Status,buf,data_len,&PHdr);
//  HandleError(DBG_TCP_DBUG,"%s update to 0x%08lx",GetNick(Status.UIN),Status.Status);
    get(app->LV_OfflineList,MUIA_NList_Entries,&total);
    for(i = 0; i<total; i++) {
      DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,i,&user);
      if (user) {
        if (user->UIN == Status.UIN) {
          user->Status = Status.Status;
//        DoMethod(app->LV_OfflineList,MUIM_NList_Redraw,i);
          DoMethod(app->LV_OfflineList,MUIM_NList_Sort);
          if (user->UWin) {
            ct = GetStatus(user->Status);
            sprintf(user->UWin->Status,ct->Status);
            sprintf(user->UWin->Title,"%ld %s (%s)",user->UIN,user->Nick,user->UWin->Status);
            set(user->UWin->WI_UserWindow,MUIA_Window_Title,user->UWin->Title);
          }
          Acty.UIN = Status.UIN;
          Acty.Timehack = time(NULL);
          Acty.Status = user->Status;
          DoMethod(app->LV_Activity,MUIM_NList_InsertSingle,&Acty,MUIV_NList_Insert_Sorted);
          break;
        }
      }
    }
    break;
  }
  case S_USER_OFFLINE: {
    char *notifycmd, cmdln[MAXNAMLEN];
    int i;
    ULONG total = 0;
    struct Activity Acty;
    struct ColorText *ct;
    struct Contact *user;
    struct S_User_Offline Offline;
    UDP_ParsePacket(&Offline,buf,data_len,&PHdr);
    get(app->LV_OfflineList,MUIA_NList_Entries,&total);
    for(i = 0; i<total; i++) {
      DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,i,&user);
      if (user) {
        if (user->UIN == Offline.UIN) {
          user->IP = user->Port = 0;
          user->Status = STATUS_OFFLINE;
//        DoMethod(app->LV_OfflineList,MUIM_NList_Redraw,i);
          DoMethod(app->LV_OfflineList,MUIM_NList_Sort);
          if (user->UWin) {
            ct = GetStatus(user->Status);
            sprintf(user->UWin->Status,ct->Status);
            sprintf(user->UWin->Title,"%ld %s (%s)",user->UIN,user->Nick,user->UWin->Status);
            set(user->UWin->WI_UserWindow,MUIA_Window_Title,user->UWin->Title);
          }
          Acty.UIN = Offline.UIN;
          Acty.Timehack = time(NULL);
          Acty.Status = STATUS_OFFLINE;
          DoMethod(app->LV_Activity,MUIM_NList_InsertSingle,&Acty,MUIV_NList_Insert_Sorted);
          get(app->STR_OfflineNotify,MUIA_String_Contents,&notifycmd);
          if (strlen(notifycmd) > 0) {
            sprintf(cmdln,notifycmd,Offline.UIN);
            System(cmdln,NULL);
          }
          break;
        }
      }
    }
    break;
  }
  case S_USER_ONLINE: {
    char *notifycmd, cmdln[MAXNAMLEN];
    int i;
    ULONG total = 0;
    struct Activity Acty;
    struct ColorText *ct;
    struct Contact *user;
    struct S_User_Online Online;
    UDP_ParsePacket(&Online,buf,data_len,&PHdr);
    get(app->LV_OfflineList,MUIA_NList_Entries,&total);
    for(i = 0; i<total; i++) {
      DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,i,&user);
      if (user) {
        if (user->UIN == Online.UIN) {
          user->IP = Online.IP;
          user->Port = Online.TCP_MsgPort;
          user->RealIP = Online.RealIP;
          user->CanTCP = Online.TCP_Flag;
          user->Status = Online.Status;
          user->LastOnline = time(NULL);
          user->Changed = TRUE;
//        HandleError(DBG_UDP_DBUG,"%s online as 0x%08lx",GetNick(Online.UIN),user->Status);
//        sprintf(err_buf,"%s IP = %s, ",GetNick(Online.UIN),Inet_NtoA(user->IP));
//        sprintf(cmdln,"RealIP = %s",Inet_NtoA(user->RealIP));
//        strcat(err_buf,cmdln);
//        HandleError(DBG_UDP_DBUG,err_buf);
//        DoMethod(app->LV_OfflineList,MUIM_NList_Redraw,i);
          DoMethod(app->LV_OfflineList,MUIM_NList_Sort);
//        HandleError(DBG_UDP_DBUG,"%s %d",user->Nick,user->CanTCP);
          if (user->UWin) {
            ct = GetStatus(user->Status);
            sprintf(user->UWin->IP,"%s:%ld",Inet_NtoA(user->IP),user->Port);
            strcpy(user->UWin->Status,ct->Status);
            set(user->UWin->TX_IP,MUIA_Text_Contents,user->UWin->IP);
            sprintf(user->UWin->Title,"%ld %s (%s)",user->UIN,user->Nick,user->UWin->Status);
            set(user->UWin->WI_UserWindow,MUIA_Window_Title,user->UWin->Title);
          }
          Acty.UIN = Online.UIN;
          Acty.Timehack = time(NULL);
          Acty.Status = user->Status;
          DoMethod(app->LV_Activity,MUIM_NList_InsertSingle,&Acty,MUIV_NList_Insert_Sorted);
          get(app->STR_OnlineNotify,MUIA_String_Contents,&notifycmd);
          if (strlen(notifycmd) > 0 && ((user->Status & 0x000000ff) == STATUS_ONLINE)) {
            sprintf(cmdln,notifycmd,Online.UIN);
            System(cmdln,NULL);
          }
          break;
        }
      }
    }
    break;
  }
  case S_END_OFFLINE_MSGS: {
    ULONG uin = 0;
    get(app->STR_ICQUIN,MUIA_String_Integer,&uin);
    Header.Command = C_ACK_MSG;
    len = UDP_CreatePacket(&Header,NULL,UDP_Buf);
    send_udp_pkt(UDP_Buf,len,uin);
    Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
    break;
  }
  case S_USER_FOUND: {
    char msg[50];
    struct Contact User;
    struct S_Basic_Info BasicInfo;
    UDP_ParsePacket(&BasicInfo,buf,data_len,&PHdr);
    PrepNewContact(&User);
    User.UIN = BasicInfo.UIN;
    User.Nick = BasicInfo.Nick;
    User.First = BasicInfo.First;
    User.Last = BasicInfo.Last;
    User.EMail = BasicInfo.EMail;
    User.Authorize = BasicInfo.Authorize;
    DoMethod(app->LV_SearchList,MUIM_NList_InsertSingle,&User,MUIV_NList_Insert_Sorted);
    sprintf(msg,"Found %d Search Hits",++found);
    set(app->TX_SearchStat,MUIA_Text_Contents,msg);
    break;
  }
  case S_INFO_REPLY: {
    struct S_Basic_Info BasicInfo;
    UDP_ParsePacket(&BasicInfo,buf,data_len,&PHdr);
    switch(UserInfoReqID[0]) {
      case INFO_VIEW:
        InfoView(&BasicInfo,INFO_BASIC);
        break;
      case INFO_REFRESH:
        InfoRefresh(&BasicInfo,INFO_BASIC);
        break;
      case INFO_GRABME:
        InfoGrabMe(&BasicInfo,INFO_BASIC);
        break;
    }
    break;
  }
  case S_EXT_INFO_REPLY: {
    struct S_Ext_Info ExtInfo;
    UDP_ParsePacket(&ExtInfo,buf,data_len,&PHdr);
    switch(UserInfoReqID[0]) {
      case INFO_VIEW:
        InfoView(&ExtInfo,INFO_EXTENDED);
        break;
      case INFO_REFRESH:
        InfoRefresh(&ExtInfo,INFO_EXTENDED);
        break;
      case INFO_GRABME:
        InfoGrabMe(&ExtInfo,INFO_EXTENDED);
        break;
    }
    break;
  }
  case S_META: {
    struct S_Meta Meta;
    UDP_ParsePacket(&Meta,buf,data_len,&PHdr);
    if (Meta.Success != META_SUCCESS) break;
//  HandleError(DBG_UDP_DBUG,"UserInfoReqID[2] = %d, PHdr.Sequence = %d",UserInfoReqID[2],PHdr.Sequence);
    if (UserInfoReqID[2] != PHdr.Sequence) break;
    switch(Meta.Subcommand) {
      case META_INFO_HOME: {
        struct Meta_Info_Home Home;
        UDP_ParseMeta(&Home,&Meta);
        switch(UserInfoReqID[0]) {
          case INFO_GRABME:
            InfoGrabMe(&Home,INFO_META_HOME);
            break;
          case INFO_REFRESH:
            InfoRefresh(&Home,INFO_META_HOME);
            break;
        }
        break;
      }
      case META_INFO_WORK: {
        struct Meta_Info_Work Work;
        UDP_ParseMeta(&Work,&Meta);
        switch(UserInfoReqID[0]) {
          case INFO_GRABME:
            InfoGrabMe(&Work,INFO_META_WORK);
            break;
        }
        break;
      }
      case META_INFO_MORE: {
        struct Meta_Info_More More;
        UDP_ParseMeta(&More,&Meta);
        switch(UserInfoReqID[0]) {
          case INFO_GRABME:
            InfoGrabMe(&More,INFO_META_MORE);
            break;
          case INFO_REFRESH:
            InfoRefresh(&More,INFO_META_MORE);
            break;
        }
        break;
      }
      case META_INFO_ABOUT: {
        struct Meta_Info_About About;
        UDP_ParseMeta(&About,&Meta);
        switch(UserInfoReqID[0]) {
          case INFO_GRABME:
            InfoGrabMe(&About,INFO_META_ABOUT);
            break;
          case INFO_REFRESH:
            InfoRefresh(&About,INFO_META_ABOUT);
            break;
        }
        break;
      }
    }
    break;
  }
  case S_END_OF_SEARCH: {
    char msg[50];
    struct S_End_Of_Search Search;
    UDP_ParsePacket(&Search,buf,data_len,&PHdr);
    if (Search.Sequence == srch_seq-1) {
      sprintf(msg,"Search Complete, Found %d Hits",found);
      set(app->TX_SearchStat,MUIA_Text_Contents,msg);
    }
    break;
  }
  case 0x00f0:
  case S_TOO_BUSY:
  case S_GO_AWAY: {
//  BOOL *reconnect = NULL;
//  LONG index;
//  get(app->CY_MyStatus,MUIA_Cycle_Active,&index);
//  get(app->CH_Reconnect,MUIA_Selected,&reconnect);
//  if (reconnect && index != NUM_STATUS) {
//    Reconnecting = TRUE;
//    Delay(500);
//    ConnectICQ(NULL);
//  }
//  else DisconnectICQ(NULL);
    break;
  }
  case S_SYSTEM_MESSAGE: {
    char *notifycmd;
    struct S_System_Message SysMsg;
    UDP_ParsePacket(&SysMsg,buf,data_len,&PHdr);
    URLMsg_cnt = SysMsg.Index;
    DoMethod(app->LV_AdText,MUIM_NList_Clear);
    DoMethod(app->LV_AdText,MUIM_NList_InsertWrap,SysMsg.Ad,-2,MUIV_NList_Insert_Bottom,WRAPCOL0,ALIGN_CENTER);
    set(app->TX_AdURL,MUIA_Text_Contents,SysMsg.URL);
    set(app->BT_AdGoURL,MUIA_Text_Contents,SysMsg.Button);
    DoMethod(app->App,MUIM_Application_PushMethod,app->WI_URLMessage,3,MUIM_Set,MUIA_Window_Open,TRUE);
    get(app->STR_SysMsg,MUIA_String_Contents,&notifycmd);
    if (strlen(notifycmd) > 0) System(notifycmd,NULL);
    break;
  }
/*
  case S_NEW_USER_UIN: {
    UWORD X1 = 0;
    ULONG uin = 0, rnd = 0;
    revmemcpy((char *)&X1,buf+len,2); len += 2;
    revmemcpy((char *)&uin,buf+len,4); len += 4;
    revmemcpy((char *)&rnd,buf+len,4); len += 4;
    set(app->STR_ICQUIN,MUIA_String_Integer,uin);
    ConnectICQ(NULL);
    break;
  }
*/
  case S_REPLY_X1:
    break;
  case S_TCP_REQUEST: {
    UBYTE type = SOCK_MESSAGE;
    struct Contact *user;
    struct Sockets *socks;
    struct S_TCP_Request Req;
    UDP_ParsePacket(&Req,buf,data_len,&PHdr);
    user = GetContact(Req.Remote_UIN);
    if (user->Type == TCP_MSG_CHAT) {
      type = SOCK_CHAT;
      if (!user->ChatListen) user->ChatListen = OpenTCPListen(type);
    }
    if (user->Type == TCP_MSG_FILE) {
      type = SOCK_FILE;
      if (!FileListen) FileListen = OpenTCPListen(type);
    }
    if (Req.IP == 0) Req.IP = user->IP;
    HandleError(DBG_TCP_DBUG,"Attempting reverse connect to %s %s:%ld",user->Nick,Inet_NtoA(Req.IP),Req.Port);
    if (!OpenTCPSocket(user,type,Req.IP,Req.Port)) {
      if (!OpenTCPSocket(user,type,user->RealIP,Req.Port)) {
        HandleError(DBG_TCP_ERRS,"Could not open a reverse TCP connection to %s.",user->Nick);
        HandleError(DBG_OTH_INFO,"Reverse connect failed!");
      }
    }
    if (socks = GetSocketFmContact(user,type)) {
      socks->Backward = TRUE;
      HandleError(DBG_OTH_INFO,"  Reverse connect succeded!");
    }
    user->Type = TCP_MSG_MSG;
    break;
  }
  case S_UPDATE_REPLY:
  case S_UPDATE_EXT_REPLY:
  case S_UPDATE_AUTH_REPLY:
  case S_INFO_NOT_FOUND:
  case S_EXT_INFO_NOT_FOUND:
  case S_MULTI:
    break;
  default:
    PrintHex(DBG_UDP_DBUG,"Unprocessed UDP Packet",buf,data_len);
}

return;

}


APTR __asm AddMsg(REG(a2) APTR pool, REG(a1) struct ICQMessage *msg)

{

struct ICQMessage *newmsg = NULL;

if (!(newmsg = AllocPooled(pool,sizeof(struct ICQMessage)))) return(NULL);

newmsg->UIN = msg->UIN;
newmsg->Timehack = msg->Timehack;
newmsg->Type = msg->Type;

if (!(newmsg->Msg = AllocPooled(pool,strlen(msg->Msg)+1))) {
  FreePooled(pool,newmsg,sizeof(struct ICQMessage));
  return(NULL);
}
strcpy(newmsg->Msg,msg->Msg);

return(newmsg);

}


void __asm RemMsg(REG(a2) APTR pool, REG(a1) struct ICQMessage *newmsg)

{

FreePooled(pool,newmsg->Msg,strlen(newmsg->Msg)+1);
FreePooled(pool,newmsg,sizeof(struct ICQMessage));

return;

}


LONG __asm CmpMsg(REG(a1) struct ICQMessage *m1, REG(a2) struct ICQMessage *m2)

{

if (m1->UIN < m2->UIN) return(-1);
if (m1->UIN > m2->UIN) return(1);

return(0);

}


void __asm DisplayMsg(REG(a2) char **array, REG(a1) struct ICQMessage *msg)

{

BOOL *usebeats;

static char uin[100], tme[15];

get(app->CH_UseBeats,MUIA_Selected,&usebeats);

if (msg) {
  switch(msg->UIN) {
    case 0x00000000:
      strcpy(uin," ");
      break;
    case 0x00000019:
    case 0x0000000a:
      switch(msg->Type) {
        case 0x0004:
          strcpy(uin,"Web Message");
          break;
        case 0x000a:
          strcpy(uin,"Query Reply");
          break;
        case 0x0019:
          strcpy(uin,"ICQ Hint");
          break;
      }
      break;
    default:
      if (msg->Type == 0x004) strcpy(uin," ");
      else strcpy(uin,GetNick(msg->UIN));
  }
  if (msg->UIN) {
    if (usebeats) sprintf(tme,"@ %d",MakeBeats(msg->Timehack));
    else strncpy(tme,ctime(&msg->Timehack)+11,8);
  }
  else strcpy(tme," ");
  *array++ = uin;
  *array++ = tme;
  *array   = msg->Msg;
}
else {
  *array++ = "Sender";
  *array++ = "Time";
  *array   = "Message";
}

return;

}


ULONG __asm TimeDispatcher(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg)

{

switch(msg->MethodID) {
  case OM_NEW:
    return(TIME_New(cl,obj,(APTR)msg));
  case OM_SET:
    return(TIME_Set(cl,obj,(APTR)msg));
  case OM_DISPOSE:
    return(TIME_Dispose(cl,obj,(APTR)msg));
  case TIME_AddApp:
    return(TIME_Setup(cl,obj,(APTR)msg));
  case TIME_RemApp:
    return(TIME_Cleanup(cl,obj,(APTR)msg));
  case TIME_Trigger:
    return(TIME_Trigger_cl(cl,obj,(APTR)msg));
  case TIME_Trigger1:
    return(TIME_Trigger_cl1(cl,obj,(APTR)msg));
  case TIME_Trigger2:
    return(SendAFile(cl,obj,(APTR)msg));
  case TIME_Trigger_Parse:
    return(ParseUDPCommands (cl,obj,(APTR)msg));
}

return(DoSuperMethodA(cl,obj,msg));

}


ULONG TIME_New(struct IClass *cl, Object *obj, Msg msg)

{

struct TimeData *data;
struct TagItem *tags, *tag;

//HandleError(DBG_OTH_INFO,"In TIME_New");

if (!(obj = (Object *)DoSuperMethodA(cl,obj,msg))) return(FALSE);

data = INST_DATA(cl,obj);

data->Socket = 0;

for(tags = ((struct opSet *)msg)->ops_AttrList; tag = NextTagItem(&tags); ) {
  switch(tag->ti_Tag) {
    case TIME_SetSecs:
      data->Seconds = tag->ti_Data;
      break;
    case TIME_SetMicro:
      data->Micros = tag->ti_Data;
      break;
    case TIME_SetTrg:
      data->Trigger = tag->ti_Data;
      break;
    case TIME_SetSock:
      data->Socket = tag->ti_Data;
      break;
  }
}

if (data->port = CreateMsgPort()) {
  if (data->req_hbeat = CreateIORequest(data->port,sizeof(struct timerequest))) {
    if (!OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)data->req_hbeat,0)) {
      data->ihnode.ihn_Object = obj;
      data->ihnode.ihn_Signals = 1<<data->port->mp_SigBit;
      data->ihnode.ihn_Method = data->Trigger;
      data->ihnode.ihn_Flags = 0;
      return((ULONG)obj);
    }
  }
}

CoerceMethod(cl,obj,OM_DISPOSE);

return(FALSE);

}


ULONG TIME_Set(struct IClass *cl, Object *obj, Msg msg)

{

struct TimeData *data = INST_DATA(cl,obj);
struct TagItem *tags, *tag;

//HandleError(DBG_OTH_INFO,"In TIME_Set.");

for(tags = ((struct opSet *)msg)->ops_AttrList; tag = NextTagItem(&tags); ) {
  switch(tag->ti_Tag) {
    case TIME_SetSecs:
      data->Seconds = tag->ti_Data;
      break;
    case TIME_SetMicro:
      data->Micros = tag->ti_Data;
      break;
    case TIME_SetTrg:
      data->Trigger = tag->ti_Data;
      break;
    case TIME_SetSock:
      data->Socket = tag->ti_Data;
      break;
  }
}

return(DoSuperMethodA(cl,obj,msg));

}


ULONG TIME_Dispose(struct IClass *cl, Object *obj, Msg msg)

{

struct TimeData *data = INST_DATA(cl,obj);

//HandleError(DBG_OTH_INFO,"In TIME_Dispose");

if (data->req_hbeat) {
  if (data->req_hbeat->tr_node.io_Device) {
    CloseDevice((struct IORequest *)data->req_hbeat);
  }
  DeleteIORequest(data->req_hbeat);
}

if (data->port) DeleteMsgPort(data->port);

return(DoSuperMethodA(cl,obj,msg));

}


ULONG TIME_Setup(struct IClass *cl, Object *obj, Msg msg)

{

struct TimeData *data = INST_DATA(cl,obj);

//HandleError(DBG_OTH_INFO,"In TIME_Setup");

data->App = ((struct MUIP_PT_AddApp *)msg)->App;

data->req_hbeat->tr_node.io_Command = TR_ADDREQUEST;
data->req_hbeat->tr_time.tv_secs = data->Seconds;
data->req_hbeat->tr_time.tv_micro = data->Micros;

SendIO((struct IORequest *)data->req_hbeat);

DoMethod(data->App,MUIM_Application_AddInputHandler,&data->ihnode);

return(TRUE);

}


ULONG TIME_Cleanup(struct IClass *cl, Object *obj, Msg msg)

{

struct TimeData *data = INST_DATA(cl,obj);

//HandleError(DBG_OTH_INFO,"In TIME_Cleanup");

DoMethod(data->App,MUIM_Application_RemInputHandler,&data->ihnode);

if (!CheckIO((struct IORequest *)data->req_hbeat)) AbortIO((struct IORequest *)data->req_hbeat);
WaitIO((struct IORequest *)data->req_hbeat);

return(DoSuperMethodA(cl,obj,msg));

}


ULONG TIME_Trigger_cl(struct IClass *cl, Object *obj, Msg msg)

{

int i;

ULONG total;

struct Sockets *socks;
struct TimeData *data = INST_DATA(cl,obj);

//HandleError(DBG_OTH_INFO,"In TIME_Trigger");

if (CheckIO((struct IORequest *)data->req_hbeat)) {
//HandleError(DBG_OTH_INFO,"In Timer heartbeat.");
  WaitIO((struct IORequest *)data->req_hbeat);
  data->req_hbeat->tr_node.io_Command = TR_ADDREQUEST;
  data->req_hbeat->tr_time.tv_secs = data->Seconds;
  data->req_hbeat->tr_time.tv_micro = data->Micros;
  SendIO((struct IORequest *)data->req_hbeat);
  if (Online) SendPing();
  get(app->LV_SockList,MUIA_NList_Entries,&total);
  for(i = 0; i < total; i++) {
    DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
    if (socks) {
      if (socks->Dir == TCP_DIR_OUT && socks->Type != SOCK_UDP) {
        if (time(NULL)-(socks->Timehack) > 360) {
          DelSockets(socks->Socket);
          i--;
          total--;
        }
      }
      if (socks->Dir == TCP_DIR_IN && socks->Type != SOCK_UDP) {
        if (time(NULL)-(socks->Timehack) > 420) {
          DelSockets(socks->Socket);
          i--;
          total--;
        }
      }
    }
  }
  return(TRUE);
}

return(FALSE);

}


ULONG TIME_Trigger_cl1(struct IClass *cl, Object *obj, Msg msg)

{

BOOL flag = FALSE;

int i;

time_t temp;

ULONG total, uin, secs, index = 0;

struct ICQLog *log;
struct TimeData *data = INST_DATA(cl,obj);

//HandleError(DBG_UDP_DBUG,"In TIME_Trigger 1");

if (CheckIO((struct IORequest *)data->req_hbeat)) {
//HandleError(DBG_OTH_INFO,"In Timer command timeout.");
  WaitIO((struct IORequest *)data->req_hbeat);
  data->req_hbeat->tr_node.io_Command = TR_ADDREQUEST;
  data->req_hbeat->tr_time.tv_secs = data->Seconds;
  data->req_hbeat->tr_time.tv_micro = data->Micros;
  SendIO((struct IORequest *)data->req_hbeat);
  get(app->LV_ICQCliLog,MUIA_NList_Entries,&total);
  if ((total > 1 && Online) || (total == 1)) {
    for(i = 0; i < total; i++) {
      DoMethod(app->LV_ICQCliLog,MUIM_NList_GetEntry,i,&log);
      if (log) {
        if (log->Pkt) {
//        HandleError(DBG_UDP_DBUG,"log->Seq = %d, log->Resend = %d",log->Seq,log->Resend);
          if (log->Resend > 5) DisconnectICQ(NULL);
          else {
            if (time(NULL)-log->Timehack > 5 && log->Cmd != TCP_MESSAGE) {
//            HandleError(DBG_UDP_DBUG,"Found an unacknowledged packet seq %d.",log->Seq);
              get(app->STR_ICQUIN,MUIA_String_Integer,&uin);
              send_udp_pkt(log->Pkt,log->Len,uin);
              log->Resend++;
              log->Timehack = time(NULL);
            }
          }
        }
      }
    }
  }
  if (LastSend && Online) {
    for(i = 0; i < 5; i++) {
      get(app->STR_TimedStatus[i],MUIA_String_Integer,&secs);
      if (secs) {
        if (time(NULL)-LastSend > secs) {
          get(app->CY_SetStatus[i],MUIA_Cycle_Active,&index);
          flag = TRUE;
        }
      }
    }
  }
  if (flag) {
    temp = LastSend;
    set(app->CY_MyStatus,MUIA_Cycle_Active,index);
    LastSend = temp;
  }
  return(TRUE);
}

return(FALSE);

}


void SendPing(void)

{

char sbuf2[30];

int len;

ULONG uin = 0;

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);

Header.Command = C_KEEP_ALIVE;

len = UDP_CreatePacket(&Header,NULL,sbuf2);

send_udp_pkt(sbuf2,len,uin);

Add2Log(LOG_CLIENT,&Header,FALSE,len,sbuf2);

return;

}


void __asm SendMessage(REG(a2) APTR obj)

{

char sendto[100], nick[100];

ULONG localin = 0;

struct ICQMessage *msg;

if (!Online) {
  HandleError(DBG_OTH_INFO,"Connect to ICQ first.");
  return;
}

get(app->STR_ICQUIN,MUIA_String_Integer,&localin);

DoMethod(app->LV_Msgs,MUIM_NList_GetEntry,MUIV_NList_GetEntry_Active,&msg);
if (msg) {
  BOOL flag = FALSE;
  int i;
  ULONG total = 0;
  struct Contact *user;
  if (msg->UIN == 0 || msg->UIN == 10) return;
  get(app->LV_OfflineList,MUIA_NList_Entries,&total);
  for(i = 0; i<total; i++) {
    DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,i,&user);
    if (user) {
      if (user->UIN == msg->UIN) {
        strcpy(nick,user->Nick);
        sprintf(sendto,"%ld %s",user->UIN,nick);
        flag = TRUE;
      }
    }
  }
  if (!flag) sprintf(sendto,"%ld",msg->UIN);
}
else {
  HandleError(DBG_OTH_INFO,"Select a message in the Message Window first.");
  return;
}

if (obj == app->BT_OpenURLWin) {
  set(app->STR_Desc,MUIA_Textinput_Contents,NULL);
  set(app->STR_URL,MUIA_Textinput_Contents,NULL);
  set(app->TX_SendURLto,MUIA_Text_Contents,sendto);
  set(app->WI_SendURL,MUIA_Window_Open,TRUE);
  set(app->WI_SendURL,MUIA_Window_ActiveObject,app->STR_Desc);
}
else {
  if (obj) {
    set(app->TI_Message,MUIA_Textinput_Contents,NULL);
    set(app->TX_Sendto,MUIA_Text_Contents,sendto);
    set(app->WI_Send,MUIA_Window_Open,TRUE);
    set(app->WI_Send,MUIA_Window_ActiveObject,app->TI_Message);
  }
}

return;

}


void __asm SendMsg2ICQ(REG(a2) APTR obj)

{

char *sendto = NULL, *msg = NULL, url[1024], *p1, *p2;

UWORD type = 0x0001;

ULONG userid = 0, id = 0;

struct Contact *user;

if (!Online) return;

get(obj,MUIA_UserData,&id);

user = GetContact(id);

if (obj == app->BT_Sendit)  set(app->WI_Send,MUIA_Window_Open,FALSE);
if (obj == app->BT_URLSend) set(app->WI_SendURL,MUIA_Window_Open,FALSE);

if (obj == app->TI_QuickMsg || obj == app->BT_Auth) {
  get(app->TX_QuickTo,MUIA_Text_Contents,&sendto);
  get(app->TI_QuickMsg,MUIA_Textinput_Contents,&msg);
  if (obj == app->BT_Auth) type = 0x0008;
}
else {
  if (obj == app->BT_URLSend) {
    type = 0x0004;
    get(app->TX_SendURLto,MUIA_Text_Contents,&sendto);
    get(app->STR_Desc,MUIA_Textinput_Contents,&p1);
    get(app->STR_URL,MUIA_Textinput_Contents,&p2);
    sprintf(url,"%s\376%s",p1,p2);
    msg = url;
  }
  else {
    get(app->TX_Sendto,MUIA_Text_Contents,&sendto);
    get(app->TI_Message,MUIA_Textinput_Contents,&msg);
  }
}

StrToLong(sendto,(LONG *)&userid);

if (userid == 0) return;

SendAMessage(obj,userid,msg,type,MSG_BOTH,MSG_VIA_BEST);

return;

}


void __asm SendMsg2ICQa(REG(a2) APTR obj)

{

BOOL *multi = NULL;

char *msg = NULL, url[1024], *p1, *p2, msg2[512], *c, *d;

LONG sel = MUIV_NList_NextSelected_Start;

UWORD type = 0x0001;

ULONG id = 0;

struct Contact *user;

get(obj,MUIA_UserData,&id);

if (!(user = GetContact(id))) return;

if (!Online && user->CanTCP == 6) return;

if (obj == user->UWin->TI_QuickMsg) {
  get(user->UWin->TI_QuickMsg,MUIA_Textinput_Contents,&msg);
}
else {
  if (obj == user->UWin->BT_URLSend) {
    type = 0x0004;
    get(user->UWin->STR_Desc,MUIA_Textinput_Contents,&p1);
    get(user->UWin->STR_URL,MUIA_Textinput_Contents,&p2);
    sprintf(url,"%s\376%s",p1,p2);
    msg = url;
  }
  else {
    if (obj == user->UWin->BT_Auth) {
      type = 0x0008;
      msg = "auth";
      obj = app->BT_Auth;
    }
  }
}

for(c = msg, d = msg2; *c; c++, d++) {
  if (*c == '\n') *d++ = '\r';
  *d = *c;
}
*d = '\0';

SendAMessage(obj,id,msg2,type,MSG_BOTH,MSG_VIA_BEST);

get(user->UWin->CH_MultiSend,MUIA_Selected,&multi);

if ((type == 0x0001 || type == 0x0004) && multi) {
  DoMethod(app->LV_OfflineList,MUIM_NList_NextSelected,&sel);
  while(sel != MUIV_NList_NextSelected_End) {
    DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,sel,&user);
    if (user->UIN != id) SendAMessage(obj,user->UIN,msg2,type,MSG_BOTH,MSG_VIA_BEST);
    DoMethod(app->LV_OfflineList,MUIM_NList_NextSelected,&sel);
  }
}

set(user->UWin->WI_UserWindow,MUIA_Window_ActiveObject,user->UWin->TI_QuickMsg);

return;

}


void SendAMessage(APTR obj, ULONG to, char *msg, UWORD type, UBYTE both, int sendhow)

{

BOOL *auto_ch;

char tomsg[100], *c, url[1024], uinlog[MAXNAMLEN];

int len;

ULONG uin, index = 0;

UWORD length = 0;

UWORD status2;

struct AsyncFile *logfh = NULL;
struct Contact *user;
struct C_SendMessage SMsg;
struct ICQLog Log;
struct ICQMessage Msg;

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);
get(app->CY_MyStatus,MUIA_Cycle_Active,&index);

if (user = GetContact(to)) if (!user->UWin) if (!CreateUserWin(to)) user = NULL;

status2 = TCPCodes[index];

sprintf(tomsg,"Sent to: %s",GetNick(to));

if (!ARexx) msg = PreParseMsg(to,type,msg);

if (obj != app->BT_Auth) {
  if ((length = strlen(msg)+1) == 1) {
    if (user) set(user->UWin->TI_QuickMsg,MUIA_Textinput_Contents,NULL);
    set(app->TI_QuickMsg,MUIA_Textinput_Contents,NULL);
    return;
  }
//c = msg;
//while(c = strchr(c,'\n')) *c = ' ';
}
else length = 2;

if (both == MSG_BOTH || both == MSG_REMOTE) {
  SMsg.ToUIN = to;
  SMsg.Type = type;
  SMsg.Message = msg;
  Log.Cmd = Header.Command = C_SEND_MESSAGE;
  Log.Len = 0;
  Log.Pkt = NULL;
  if (sendhow == MSG_VIA_UDP || obj == app->BT_Auth) {
    len = UDP_CreatePacket(&Header,&SMsg,UDP_Buf);
    send_udp_pkt(UDP_Buf,len,uin);
    Log.Seq = Header.Sequence;
    Log.Se2 = Header.Sequence2;
    Log.Len = len;
    Log.Pkt = UDP_Buf;
  }
  else {
    if (SendTCPMessage(to,msg,TCP_MESSAGE,type,TCP_MSG_REAL,TCP_Seq,LINE,0x00000000,0x0000,0)) {
      Header.TCP_Sequence = Log.Seq = TCP_Seq;
      Header.Command = Log.Cmd = TCP_MESSAGE;
      Header.Sequence2 = 0;
      TCP_Seq--;
    }
    else {
      len = UDP_CreatePacket(&Header,&SMsg,UDP_Buf);
      send_udp_pkt(UDP_Buf,len,uin);
      Log.Seq = Header.Sequence;
      Log.Se2 = Header.Sequence2;
      Log.Len = len;
      Log.Pkt = UDP_Buf;
    }
  }
  Add2Log(LOG_CLIENT,&Header,FALSE,Log.Len,Log.Pkt);
  if (user) {
    user->LastMessageTo = time(NULL);
    user->Changed = TRUE;
  }
}

if (both == MSG_REMOTE) return;

Msg.Type = type;
Msg.Timehack = time(NULL);
Msg.UIN = uin;
Msg.Msg = msg;

sprintf(uinlog,"%sUsers/%ld/Logs/%ld",currentdir,uin,to);

get(app->CH_NoMsgLog,MUIA_Selected,&auto_ch);

if (!auto_ch) if (logfh = OpenAsync(uinlog,MODE_APPEND,AsyncBuf)) WriteLineAsync(logfh,ctime(&Msg.Timehack));

if (obj == app->BT_Auth || obj == user->UWin->BT_Auth) Msg.Msg = "Authorization to add to Contact List.";

if (type == 0x0004) {
  Msg.Type = 1;
  c = strchr(Msg.Msg,'\xFE');
  *c = '\0';
  DoMethod(app->LV_Msgs,MUIM_NList_InsertSingleWrap,&Msg,MUIV_NList_Insert_Bottom,WRAPCOL2,ALIGN_LEFT);
  if (user) DoMethod(user->UWin->LV_Msgs,MUIM_NList_InsertSingleWrap,&Msg,MUIV_NList_Insert_Bottom,WRAPCOL2,ALIGN_LEFT);
  if (logfh) {
    WriteLineAsync(logfh,"S: ");
    WriteLineAsync(logfh,Msg.Msg);
    WriteCharAsync(logfh,'\n');
  }
  Msg.Type = 4;
  sprintf(url,"\x1Bu%s",c+1);
  Msg.Msg = url;
}

DoMethod(app->LV_Msgs,MUIM_NList_InsertSingleWrap,&Msg,MUIV_NList_Insert_Bottom,WRAPCOL2,ALIGN_LEFT);
if (user) DoMethod(user->UWin->LV_Msgs,MUIM_NList_InsertSingleWrap,&Msg,MUIV_NList_Insert_Bottom,WRAPCOL2,ALIGN_LEFT);

if (logfh) {
  WriteLineAsync(logfh,"S: ");
  WriteLineAsync(logfh,Msg.Msg);
  WriteLineAsync(logfh,"\n\n");
  CloseAsync(logfh);
  SetComment(uinlog,GetNick(to));
}

Msg.UIN = 0;
Msg.Type = 1;
Msg.Msg = tomsg;

DoMethod(app->LV_Msgs,MUIM_NList_InsertSingleWrap,&Msg,MUIV_NList_Insert_Bottom,WRAPCOL2,ALIGN_LEFT);

Msg.Msg = LINE;

DoMethod(app->LV_Msgs,MUIM_NList_InsertSingleWrap,&Msg,MUIV_NList_Insert_Bottom,WRAPCOL2,ALIGN_LEFT);
if (user) DoMethod(user->UWin->LV_Msgs,MUIM_NList_InsertSingleWrap,&Msg,MUIV_NList_Insert_Bottom,WRAPCOL2,ALIGN_LEFT);

DoMethod(app->LV_Msgs,MUIM_NList_Jump,MUIV_NList_Jump_Bottom);
if (user) DoMethod(user->UWin->LV_Msgs,MUIM_NList_Jump,MUIV_NList_Jump_Bottom);

if (obj == app->TI_QuickMsg) set(app->TI_QuickMsg,MUIA_Textinput_Contents,NULL);
if (obj == user->UWin->TI_QuickMsg) set(user->UWin->TI_QuickMsg,MUIA_Textinput_Contents,NULL);

return;

}


void __asm GetUINInfo(REG(a2) APTR obj)

{

int len = 0;

ULONG uin, id = 0;

struct Contact *user;
struct C_Info_Req Info;
struct C_Meta Meta;
struct ICQMessage *msg;

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);

get(obj,MUIA_UserData,&id);

if (obj == app->BT_GetInfo3) {
  DoMethod(app->LV_SearchList,MUIM_NList_GetEntry,MUIV_NList_GetEntry_Active,&user);
  if (user) {
    Meta.Subcommand = META_REQ_INFO_1;
    Meta.UIN = Info.UIN = UserInfoReqID[1] = user->UIN;
    UserInfoReqID[0] = INFO_VIEW;
  }
  else {
    HandleError(DBG_OTH_INFO,"Select a Nick from the list first.");
    return;
  }
}
else {
  if (obj == app->BT_GetInfo) {
    DoMethod(app->LV_Msgs,MUIM_NList_GetEntry,MUIV_NList_GetEntry_Active,&msg);
    if (msg) {
      Meta.Subcommand = META_REQ_INFO_1;
      Meta.UIN = Info.UIN = UserInfoReqID[1] = msg->UIN;
      UserInfoReqID[0] = INFO_VIEW;
    }
    else {
      HandleError(DBG_OTH_INFO,"Select a message from the message list first.");
      return;
    }
  }
  else {
    if (obj == app->BT_GrabMyStats) {
      Meta.Subcommand = META_REQ_GRABME_1;
      Meta.UIN = Info.UIN = UserInfoReqID[1] = uin;
      UserInfoReqID[0] = INFO_GRABME;
    }
    else {
      if (obj == app->BT_AddUIN) {
        Meta.Subcommand = META_REQ_INFO_1;
        Meta.UIN = Info.UIN = UserInfoReqID[1] = id;
        UserInfoReqID[0] = INFO_VIEW;
      }
      else {
        Meta.Subcommand = META_REQ_INFO_1;
        Meta.UIN = Info.UIN = UserInfoReqID[1] = id;
        UserInfoReqID[0] = INFO_REFRESH;
      }
    }
  }
}

switch(Header.Version) {
  case 0x0002:
    Header.Command = C_INFO_REQ;
    Info.Sequence = UserInfoReqID[2] = info_seq;
    len = UDP_CreatePacket(&Header,&Info,UDP_Buf);
    info_seq = Info.Sequence;
    send_udp_pkt(UDP_Buf,len,uin);
    Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
    Header.Command = C_EXT_INFO_REQ;
    Info.Sequence = extinfo_seq;
    len = UDP_CreatePacket(&Header,&Info,UDP_Buf);
    extinfo_seq = Info.Sequence;
    send_udp_pkt(UDP_Buf,len,uin);
    Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
    break;
  case 0x0005:
    Header.Command = C_META;
    len = UDP_CreatePacket(&Header,&Meta,UDP_Buf);
    UserInfoReqID[2] = Header.Sequence;
    send_udp_pkt(UDP_Buf,len,uin);
    Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
    break;
}

DoMethod(app->WI_Information,MUIM_MultiSet,MUIA_Text_Contents,NULL,app->STR_UserUIN,app->STR_UserEMail,app->STR_UserAuth,
  app->TX_UserCity,app->TX_UserCountry,app->TX_UserState,app->TX_UserAge,app->TX_UserSex,app->TX_UserPhone,app->TX_UserURL,NULL);

DoMethod(app->WI_Information,MUIM_MultiSet,MUIA_Textinput_Contents,NULL,app->STR_UserNick,app->STR_UserFirst,app->STR_UserLast,NULL);

set(app->NU_UserZone,MUIA_Numeric_Value,0);

DoMethod(app->LV_UserAbout,MUIM_NList_Clear);

return;

}


void __asm AddContact(REG(a2) APTR obj)

{

char *email, *nick, *first, *last;

int len;

BOOL *check;

ULONG uin = 0, localin = 0;

struct C_Info_Req Info;
struct C_Search_User Search;

set(app->WI_Searches,MUIA_Window_Open,FALSE);

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);
get(app->CH_SearchUIN,MUIA_Selected,&check);

if (check) {
  get(app->STR_SrchUIN,MUIA_Textinput_Integer,&localin);
  Header.Command = C_INFO_REQ;
  Info.Sequence = UserInfoReqID[2] = info_seq++;
  Info.UIN = UserInfoReqID[1] = localin;
  len = UDP_CreatePacket(&Header,&Info,UDP_Buf);
  send_udp_pkt(UDP_Buf,len,uin);
  Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
  Header.Command = C_EXT_INFO_REQ;
  Info.Sequence = extinfo_seq++;
  len = UDP_CreatePacket(&Header,&Info,UDP_Buf);
  send_udp_pkt(UDP_Buf,len,uin);
  Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
  DoMethod(app->WI_Information,MUIM_MultiSet,MUIA_Text_Contents,NULL,app->STR_UserUIN,app->STR_UserEMail,app->STR_UserAuth,
    app->TX_UserCity,app->TX_UserCountry,app->TX_UserState,app->TX_UserAge,app->TX_UserSex,app->TX_UserPhone,app->TX_UserURL,NULL);
  DoMethod(app->WI_Information,MUIM_MultiSet,MUIA_Textinput_Contents,NULL,app->STR_UserNick,app->STR_UserFirst,app->STR_UserLast,NULL);
  DoMethod(app->LV_UserAbout,MUIM_NList_Clear);
  UserInfoReqID[0] = INFO_VIEW;
  return;
}

email = nick = first = last = "";

get(app->CH_SearchEMail,MUIA_Selected,&check);

if (check) get(app->STR_SrchEMail,MUIA_Textinput_Contents,&email);

get(app->CH_SearchName,MUIA_Selected,&check);

if (check) {
  get(app->STR_SrchNick,MUIA_Textinput_Contents,&nick);
  get(app->STR_SrchFirst,MUIA_Textinput_Contents,&first);
  get(app->STR_SrchLast,MUIA_Textinput_Contents,&last);
}

Header.Command = C_SEARCH_USER;

Search.Sequence = srch_seq++;

strcpy(Search.Nick,nick);
strcpy(Search.First,first);
strcpy(Search.Last,last);
strcpy(Search.EMail,email);

len = UDP_CreatePacket(&Header,&Search,UDP_Buf);

send_udp_pkt(UDP_Buf,len,uin);

DoMethod(app->LV_SearchList,MUIM_NList_Clear);

found = 0;

set(app->TX_SearchStat,MUIA_Text_Contents,"Searching...");
set(app->WI_SrchResults,MUIA_Window_Open,TRUE);

Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);

return;

}


void __asm AddUpdate(REG(a2) APTR obj)

{

BOOL flag = FALSE, seeinvis, newmsg, beinvis;

char *uin, *auth, *tmp1;
char nick[50], first[50], last[50], email[50], cmnt[256], about[512];

int i, len;

LONG zone, line = -1;

ULONG total, localin = 0, stat = STATUS_OFFLINE, ip, port, realip, tmp2;

struct Contact User, *user;
struct C_ContactList CList;
struct MUI_NList_GetEntryInfo res;
struct FileWin *FWin = NULL;
struct UserWindow *UWin = NULL;

PrepNewContact(&User);

cmnt[0] = '\0';

ip = port = realip = 0;

beinvis = seeinvis = newmsg = FALSE;

if (obj == app->BT_AddUpdate2) {
  DoMethod(app->LV_SearchList,MUIM_NList_GetEntry,MUIV_NList_GetEntry_Active,&user);
  if (user) {
    User.UIN = user->UIN;
    strcpy(nick,user->Nick);
    User.Nick = nick;
    strcpy(first,user->First);
    User.First = first;
    strcpy(last,user->Last);
    User.Last = last;
    strcpy(email,user->EMail);
    User.EMail = email;
    User.Authorize = user->Authorize;
    ip = user->IP;
    port = user->Port;
    realip = user->RealIP;
    stat = user->Status;
    seeinvis = user->SeeInvis;
    beinvis = user->BeInvis;
    User.City = User.State = User.Phone = User.HomePage = User.About = User.Comment = NULL;
    User.Country = User.Age = 0xffff;
    User.Sex = 0x00;
  }
  else {
    HandleError(DBG_OTH_INFO,"Select a Nick from the Search Results List first.");
    return;
  }
}
else {
  get(app->STR_UserUIN,MUIA_Text_Contents,&uin);
  if (!uin) return;
  StrToLong(uin,(LONG *)&User.UIN);
  get(app->STR_UserNick,MUIA_Textinput_Contents,&User.Nick);
  get(app->STR_UserFirst,MUIA_Textinput_Contents,&User.First);
  get(app->STR_UserLast,MUIA_Textinput_Contents,&User.Last);
  get(app->STR_UserEMail,MUIA_Text_Contents,&User.EMail);
  get(app->STR_UserAuth,MUIA_Text_Contents,&auth);
  if (!strcmp(auth,"Yes")) User.Authorize = 0x00;
  else User.Authorize = 0x01;
  get(app->TX_UserCity,MUIA_Text_Contents,&User.City);
  get(app->TX_UserCountry,MUIA_Text_Contents,&tmp1);
  if (!strcmp(tmp1,"Unspecified")) tmp2 = 0xffff;          // Enforcer hits here if Ext. pkt does not come in...
  else StrToLong(tmp1,(LONG *)&tmp2);
  User.Country = tmp2;
  get(app->NU_UserZone,MUIA_Numeric_Value,&zone);
  User.TimeZone = zone;
  get(app->TX_UserState,MUIA_Text_Contents,&User.State);
  get(app->TX_UserAge,MUIA_Text_Contents,&tmp1);
  if (!strcmp(tmp1,"Unspecified")) tmp2 = 0xffff;
  else StrToLong(tmp1,(LONG *)&tmp2);
  User.Age = tmp2;
  get(app->TX_UserSex,MUIA_Text_Contents,&tmp1);
  if (!strcmp(tmp1,"Unspecified")) tmp2 = 0x00;
  else {
    if (!strcmp(tmp1,"Female")) tmp2 = 0x01;
    else tmp2 = 0x02;
  }
  User.Sex = tmp2;
  get(app->TX_UserPhone,MUIA_Text_Contents,&User.Phone);
  get(app->TX_UserURL,MUIA_Text_Contents,&User.HomePage);
  get(app->LV_UserAbout,MUIA_NList_Entries,&total);
  about[0] = '\0';
  for(i = 0; i < total; i++) {
    res.pos = i;
    DoMethod(app->LV_UserAbout,MUIM_NList_GetEntryInfo,&res);
    if (res.line == line) continue;
    strcat(about,(char *)res.entry);
    strcat(about,"\r\n");
    line = res.line;
  }
  User.About = about;
  User.Comment = NULL;
}

get(app->LV_OfflineList,MUIA_NList_Entries,&total);

for(i = 0; i<total; i++) {
  DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,i,&user);
  if (user) {
    if (user->UIN == User.UIN) {
      stat = user->Status;
      ip = user->IP;
      port = user->Port;
      realip = user->RealIP;
      if (user->Comment) strcpy(cmnt,user->Comment);
      User.Comment = cmnt;
      if (user->UWin) {
        user->UWin->DoNotDelete = TRUE;
        UWin = user->UWin;
      }
      if (user->FWin) {
        user->FWin->DoNotDelete = TRUE;
        FWin = user->FWin;
      }
      DoMethod(app->LV_OfflineList,MUIM_NList_Remove,i);
      if (user->Status != STATUS_NEWUIN) flag = TRUE;
      else stat = STATUS_OFFLINE;
      seeinvis = user->SeeInvis;
      beinvis = user->BeInvis;
      newmsg = user->NewMsg;
      break;
    }
  }
}

User.IP = ip;
User.Port = port;
User.RealIP = realip;
User.Status = stat;

User.SeeInvis = seeinvis;
User.BeInvis = beinvis;
User.NewMsg = newmsg;
User.UWin = NULL;

if (strlen(User.First) == 0) User.First = LINE;
if (strlen(User.Last)  == 0) User.Last  = LINE;
if (strlen(User.EMail) == 0) User.EMail = LINE;
if (strlen(User.Nick)  == 0) User.Nick  = User.First;

if (UWin) User.UWin = UWin;
if (FWin) User.FWin = FWin;

AddUser2CList(&User);

DoMethod(app->LV_OfflineList,MUIM_NList_Sort);

UpdateUserWin(GetContact(User.UIN));
SaveContact(User.UIN);

if (!flag) {
  get(app->STR_ICQUIN,MUIA_String_Integer,&localin);
  Header.Command = C_CONTACT_LIST;
  CList.UIN_Count = 1;
  CList.UIN[0] = User.UIN;
  len = UDP_CreatePacket(&Header,&CList,UDP_Buf);
  send_udp_pkt(UDP_Buf,len,localin);
  Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
  sprintf(maintitle,"STRICQ (%d)",++contacts_cnt);
  set(app->WI_Main,MUIA_Window_Title,maintitle);
}

return;

}


void SendContacts(ULONG uin, UWORD cmd)

{

int len = 0, i;

ULONG total = 0;

struct Contact *user;
struct C_ContactList CList;

get(app->LV_OfflineList,MUIA_NList_Entries,&total);

Header.Command = cmd;

for(CList.UIN_Count = i = 0; i<total; i++) {
  DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,i,&user);
  if (user) {
    if (user->Status != STATUS_NEWUIN) {
      switch(cmd) {
        case C_CONTACT_LIST:
          CList.UIN[CList.UIN_Count++] = user->UIN;
          break;
        case C_VIS_LIST:
          if (user->SeeInvis) CList.UIN[CList.UIN_Count++] = user->UIN;
          break;
        case C_INVIS_LIST:
          if (user->BeInvis) CList.UIN[CList.UIN_Count++] = user->UIN;
          break;
      }
    }
    if (CList.UIN_Count == MAX_CONTACTS_PKT) {
      len = UDP_CreatePacket(&Header,&CList,UDP_Buf);
      Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
      Delay(5);
      send_udp_pkt(UDP_Buf,len,uin);
      CList.UIN_Count = 0;
    }
  }
}

if (CList.UIN_Count > 0) {
  len = UDP_CreatePacket(&Header,&CList,UDP_Buf);
  Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
  Delay(5);
  send_udp_pkt(UDP_Buf,len,uin);
}

return;

}


void __asm ChangePW(REG(a2) APTR obj)

{

char *pw;

int len;

ULONG uin = 0;

struct C_ChangePassword Pass;

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);
get(app->STR_ICQPass,MUIA_String_Contents,&pw);

Header.Command = C_CHANGE_PASSWORD;

Pass.Sequence = pw_seq++;

strcpy(Pass.Password,pw);

len = UDP_CreatePacket(&Header,&Pass,UDP_Buf);

send_udp_pkt(UDP_Buf,len,uin);

Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);

return;

}


void __asm SetQuickTo(REG(a2) APTR obj)

{

char mesg[100], nick[100];

int i;

LONG entry = 0, total = 0;

struct Contact *user;
struct ICQMessage *msg;

get(app->LV_Msgs,MUIA_NList_EntryClick,&entry);

if (entry < 0) return;

DoMethod(app->LV_Msgs,MUIM_NList_GetEntry,entry,&msg);

if (msg->UIN == 0 || msg->UIN == 10) return;

get(app->LV_OfflineList,MUIA_NList_Entries,&total);

for(i = 0; i<total; i++) {
  DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,i,&user);
  if (user) {
    if (user->UIN == msg->UIN) {
      strcpy(nick,user->Nick);
      sprintf(mesg,"%ld %s",user->UIN,nick);
      set(app->TX_QuickTo,MUIA_Text_Contents,mesg);
      return;
    }
  }
}

sprintf(mesg,"%ld",msg->UIN);
set(app->TX_QuickTo,MUIA_Text_Contents,mesg);

return;

}


void __asm ChangeMyStatus(REG(a2) APTR obj)

{

BOOL *opts;

int len;

LONG index = 0;

ULONG uin = 0;

struct C_StatusChange Status;

get(app->CY_MyStatus,MUIA_Cycle_Active,&index);

if (Codes[index] == STATUS_OFFLINE) {
  if (Online) DisconnectICQ(NULL);
  set(app->TX_Color,MUIA_Text_Contents,"Offline");
  return;
}

if (Codes[index] != STATUS_OFFLINE && !Online) {
  ConnectICQ(NULL);
  return;
}

Status.Status = Codes[index];

get(app->CH_WebPresence,MUIA_Selected,&opts);

if (opts) Status.Status |= STATUSF_WEBPRESENCE;

get(app->CH_HideIP,MUIA_Selected,&opts);

if (opts) Status.Status |= STATUSF_HIDEIP;

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);

Header.Command = C_STATUS_CHANGE;

len = UDP_CreatePacket(&Header,&Status,UDP_Buf);

send_udp_pkt(UDP_Buf,len,uin);

Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);

return;

}


void __asm SavePrefs(REG(a2) APTR obj)

{

char line[1024], *line_p, *nick, *uinstr;

int i;

LONG total = 0;

UWORD length = 0;

struct AsyncFile *loadfh;
struct Column  *col;
struct MUI_PenSpec *startpen = NULL;
struct IgnoreUIN *ignore;

get(app->STR_ICQUIN,MUIA_String_Contents,&uinstr);

MakeFilenames(NULL);

sprintf(line,"%sUsers/%s",currentdir,uinstr);

MyCreateDir(logdir_fl);
MyCreateDir(userdir_fl);

get(app->STR_Nick,MUIA_String_Contents,&nick);
SetComment(line,nick);

if (loadfh = OpenAsync(colors_fl,MODE_WRITE,AsyncBuf)) {
  for(i = 0; i < 8; i++) {
    get(app->PP_StatusColors[i],MUIA_Pendisplay_Spec,&startpen);
    WriteAsync(loadfh,startpen,sizeof(struct MUI_PenSpec));
  }
  WriteAsync(loadfh,&URLMsg_cnt,sizeof(URLMsg_cnt));
  get(app->TI_About,MUIA_Textinput_Contents,&line_p);
  length = strlen(line_p)+1;
  WriteAsync(loadfh,&length,sizeof(length));
  WriteAsync(loadfh,line_p,length);
  WriteAsync(loadfh,&SrvrMsg_cnt,sizeof(SrvrMsg_cnt));
  for(i = 8; i < NUM_STATUS_COLORS; i++) {
    get(app->PP_StatusColors[i],MUIA_Pendisplay_Spec,&startpen);
    WriteAsync(loadfh,startpen,sizeof(struct MUI_PenSpec));
  }
  for(i = 0; i < NUM_CHAT_COLORS; i++) {
    get(app->PP_ChatColors[i],MUIA_Pendisplay_Spec,&startpen);
    WriteAsync(loadfh,startpen,sizeof(struct MUI_PenSpec));
  }
  CloseAsync(loadfh);
}


if (loadfh = OpenAsync(server_fl,MODE_WRITE,AsyncBuf)) {
  get(app->LV_ICQServers,MUIA_NList_Entries,&total);
  for(i = 0; i<total; i++) {
    DoMethod(app->LV_ICQServers,MUIM_NList_GetEntry,i,&line_p);
    if (line) {
      sprintf(line,"%s\n",line_p);
      WriteLineAsync(loadfh,line);
    }
  }
  WriteLineAsync(loadfh,";\n");
  get(app->LV_ColsStore,MUIA_NList_Entries,&total);
  for(i = 0; i<total; i++) {
    DoMethod(app->LV_ColsStore,MUIM_NList_GetEntry,i,&col);
    if (col) {
      sprintf(line,"%s\n%s\n",col->Name,col->COL);
      WriteLineAsync(loadfh,line);
    }
  }
  WriteLineAsync(loadfh,";\n");
  get(app->LV_ColsUse,MUIA_NList_Entries,&total);
  for(i = 0; i<total; i++) {
    DoMethod(app->LV_ColsUse,MUIM_NList_GetEntry,i,&col);
    if (col) {
      sprintf(line,"%s\n%s\n",col->Name,col->COL);
      WriteLineAsync(loadfh,line);
    }
  }
  WriteLineAsync(loadfh,";\n");
  get(app->LV_IgnoreUIN,MUIA_NList_Entries,&total);
  for(i = 0; i<total; i++) {
    DoMethod(app->LV_IgnoreUIN,MUIM_NList_GetEntry,i,&ignore);
    if (ignore) {
      sprintf(line,"%ld\n%s\n%ld\n%ld\n",ignore->UIN,ignore->Nick,ignore->Timehack,ignore->ExpireDays);
      WriteLineAsync(loadfh,line);
    }
  }
  WriteLineAsync(loadfh,";\n");
  CloseAsync(loadfh);
}

DoMethod(app->App,MUIM_Application_Save,config_fl);

if (loadfh = OpenAsync(lastuser_fl,MODE_WRITE,AsyncBuf)) {
  WriteAsync(loadfh,uinstr,strlen(uinstr));
  WriteCharAsync(loadfh,'\n');
  CloseAsync(loadfh);
}

DoMethod(app->DL_UINList,MUIM_Dirlist_ReRead);

SaveAllContacts();

return;

}


ULONG __asm ColorDispatcher(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg)

{

switch(msg->MethodID) {
  case OM_SET:
    return(COLOR_Set(cl,obj,(APTR)msg));
  case MUIM_Setup:
    return(COLOR_Setup(cl,obj,(APTR)msg));
  case MUIM_Cleanup:
    return(COLOR_Cleanup(cl,obj,(APTR)msg));
  case MUIM_Draw:
    return(COLOR_Draw(cl,obj,(APTR)msg));
}

return(DoSuperMethodA(cl,obj,msg));

}


ULONG COLOR_Set(struct IClass *cl, Object *obj, Msg msg)

{

struct ColorData *data = INST_DATA(cl,obj);
struct TagItem *tags, *tag;

//printf("COLOR_Set()\n");

for(tags = ((struct opSet *)msg)->ops_AttrList; tag = NextTagItem(&tags); ) {
  if ((tag->ti_Tag-TAG_USER) >= 0 && (tag->ti_Tag-TAG_USER) < NUM_STATUS_COLORS) {
//  printf("(tag->ti_Tag-TAG_USER) = %ld\n",(tag->ti_Tag-TAG_USER));
    data->StatusPens[(tag->ti_Tag-TAG_USER)] = *((struct MUI_PenSpec *)tag->ti_Data);
    data->ChangedPen[(tag->ti_Tag-TAG_USER)] = TRUE;
    MUI_Redraw(obj,MADF_DRAWOBJECT);
  }
  if ((tag->ti_Tag-100-TAG_USER) >= 0 && (tag->ti_Tag-100-TAG_USER) < NUM_CHAT_COLORS) {
//  printf("(tag->ti_Tag-100-TAG_USER) = %ld\n",(tag->ti_Tag-100-TAG_USER));
    data->ChatPens[(tag->ti_Tag-100-TAG_USER)] = *((struct MUI_PenSpec *)tag->ti_Data);
    data->ChangedChat[(tag->ti_Tag-100-TAG_USER)] = TRUE;
    MUI_Redraw(obj,MADF_DRAWOBJECT);
  }
}

return(DoSuperMethodA(cl,obj,msg));

}


ULONG COLOR_Setup(struct IClass *cl, Object *obj, Msg msg)

{

int i;

struct ColorData *data = INST_DATA(cl,obj);

//printf("COLOR_Setup()\n");

if (!DoSuperMethodA(cl,obj,msg)) return(FALSE);

for(i = 0; i < NUM_STATUS_COLORS; i++) {
  Pens.StatusColors[i] = MUI_ObtainPen(muiRenderInfo(obj),&data->StatusPens[i],0);
//printf("Pens.StatusColors[%d] = %ld\n",i,Pens.StatusColors[i]);
}

for(i = 0; i < NUM_CHAT_COLORS; i++) {
  Pens.ChatColors[i] = MUI_ObtainPen(muiRenderInfo(obj),&data->ChatPens[i],0);
//printf("Pens.ChatColors[%d] = %ld\n",i,Pens.ChatColors[i]);
}

return(TRUE);

}


ULONG COLOR_Cleanup(struct IClass *cl, Object *obj, Msg msg)

{

int i;

//struct ColorData *data = INST_DATA(cl,obj);

//printf("COLOR_Cleanup()\n");

for(i = 0; i < NUM_STATUS_COLORS; i++) MUI_ReleasePen(muiRenderInfo(obj),Pens.StatusColors[i]);

for(i = 0; i < NUM_CHAT_COLORS; i++) MUI_ReleasePen(muiRenderInfo(obj),Pens.ChatColors[i]);

return(DoSuperMethodA(cl,obj,msg));

}


ULONG COLOR_Draw(struct IClass *cl, Object *obj, struct MUIP_Draw *msg)

{

BOOL flag = TRUE;

int i;

struct ColorData *data = INST_DATA(cl,obj);

//printf("COLOR_Draw()\n");

DoSuperMethodA(cl,obj,(Msg)msg);

if (!(msg->flags & MADF_DRAWOBJECT)) return(FALSE);

for(i = 0; i < NUM_STATUS_COLORS; i++) {
  if (data->ChangedPen[i]) {
    flag = data->ChangedPen[i] = FALSE;
    MUI_ReleasePen(muiRenderInfo(obj),Pens.StatusColors[i]);
    Pens.StatusColors[i] = MUI_ObtainPen(muiRenderInfo(obj),&data->StatusPens[i],0);
//  printf("Pens.StatusColors[%d] = %ld\n",i,Pens.StatusColors[i]);
  }
}

for(i = 0; i < NUM_CHAT_COLORS; i++) {
  if (data->ChangedChat[i]) {
    data->ChangedChat[i] = FALSE;
    MUI_ReleasePen(muiRenderInfo(obj),Pens.ChatColors[i]);
    Pens.ChatColors[i] = MUI_ObtainPen(muiRenderInfo(obj),&data->ChatPens[i],0);
//  printf("Pens.ChatColors[%d] = %ld\n",i,Pens.ChatColors[i]);
  }
}

if (!flag) DoMethod(app->LV_OfflineList,MUIM_NList_Redraw,MUIV_NList_Redraw_All);

return(FALSE);

}


void ParseMessage(UWORD cmd, char *buf, ULONG uin, UWORD type)

{

BOOL *iconic = NULL;

char mesg[200], nick[100], *c, *quickmsg, url[1024];

int i;

LONG total;

struct Contact *user, User;
struct ICQMessage msg;

if (uin != 10) {
  if (!(user = GetContact(uin))) {
    PrepNewContact(&User);
    User.UIN = uin;
    sprintf(nick,"%ld",uin);
    User.Nick = nick;
    User.Status = STATUS_NEWUIN;
    AddUser2CList(&User);
    user = GetContact(uin);
  }
}
else user = NULL;

get(app->App,MUIA_Application_Iconified,&iconic);

if (iconic) set(app->App,MUIA_Application_Iconified,FALSE);

msg.UIN = uin;
msg.Type = type;
msg.Timehack = time(NULL);

user->LastMessageFm = time(NULL);
user->Changed = TRUE;

SendMessage2Script(buf,uin,type);

if (user) {
  if (user->UWin) {
    set(user->UWin->RG_UserPages,MUIA_Group_ActivePage,0);
    set(user->UWin->WI_UserWindow,MUIA_Window_ActiveObject,user->UWin->TI_QuickMsg);
  }
}

switch(type) {
  case MSG_MSG:
  case MSG_CHAT:
  case MSG_FILE: {
    struct MSG_Message Message;
    MSG_ParseMessage(type,buf,&Message);
    msg.Msg = Message.Message;
    for(c = msg.Msg; *c; c++) if (*c == '\n' || *c == '\r') *c = ' ';
    break;
  }
  case MSG_URL: {
    struct MSG_URLDesc URL;
    MSG_ParseMessage(type,buf,&URL);
    msg.Type = 1;
    msg.Msg = URL.Desc;
    StoreMessage(&msg,uin,cmd);
    msg.Timehack = 0;
    msg.Type = 4;
    sprintf(url,"\x1Bu%s",URL.URL);
    msg.Msg = url;
    break;
  }
  case MSG_REQ_AUTH: {
    struct MSG_Common ReqAuth;
    MSG_ParseMessage(type,buf,&ReqAuth);
    sprintf(url,"%s (%s %s) Requests your Authorization to add you to his/her Contact List.  Reason:  \033b%s\033n",ReqAuth.Nick,ReqAuth.First,ReqAuth.Last,ReqAuth.Message);
    msg.Msg = url;
    break;
  }
  case MSG_GIVE_AUTH:
    msg.Msg = "Authorizes you to add him/her to your Contact List.";
    break;
  case MSG_ADDED: {
    struct MSG_Common Added;
    MSG_ParseMessage(type,buf,&Added);
    sprintf(url,"You have been added to %s's (%s %s) Contact List.",Added.Nick,Added.First,Added.Last);
    msg.Msg = url;
    break;
  }
  case MSG_WEB_PAGER:
  case MSG_EMAIL_PAGER: {
    struct MSG_Common Pager;
    if (uin != 10) HandleError(DBG_OTH_INFO,"Pager msg has uin = %ld",uin);
    MSG_ParseMessage(type,buf,&Pager);
    set(app->TX_WebName,MUIA_Text_Contents,Pager.Nick);
    set(app->TX_WebEMail,MUIA_Text_Contents,Pager.EMail);
    DoMethod(app->LV_WebMsg,MUIM_NList_InsertWrap,Pager.Message,-2,MUIV_NList_Insert_Bottom,WRAPCOL0,ALIGN_LEFT);
    set(app->WI_WebPager,MUIA_Window_Open,TRUE);
    return;
  }
  case MSG_ADDUIN: {
    struct MSG_AddUIN AddUIN;
    char desc[100];
    int i;
    AddUIN.Total = 0;
    AddUIN.Next = NULL;
    DoMethod(app->LV_ToAddUIN,MUIM_NList_Clear);
    MSG_ParseMessage(type,buf,&AddUIN);
    for(i = 0; i < AddUIN.Total; i++) {
      DoMethod(app->LV_ToAddUIN,MUIM_NList_InsertSingle,&AddUIN,MUIV_NList_Insert_Sorted);
      if (i < AddUIN.Total-1) MSG_ParseMessage(type,AddUIN.Next,&AddUIN);
    }
    sprintf(desc,"New UIN(s) Received From %s",GetNick(uin));
    set(app->TX_Desc,MUIA_Text_Contents,desc);
    set(app->WI_AddUIN,MUIA_Window_ActiveObject,app->BT_AddUIN);
    set(app->WI_AddUIN,MUIA_Window_Open,TRUE);
    return;
  }
}

StoreMessage(&msg,uin,cmd);

msg.UIN = msg.Timehack = msg.Type = 0;
msg.Msg = LINE;
StoreMessage(&msg,uin,cmd);

get(app->TI_QuickMsg,MUIA_Textinput_Contents,&quickmsg);

if (!strlen(quickmsg)) {
  set(app->LV_Msgs,MUIA_NList_Active,MUIV_NList_Active_Bottom);
  set(app->LV_Msgs,MUIA_NList_Active,MUIV_NList_Active_Up);
  get(app->LV_OfflineList,MUIA_NList_Entries,&total);
  for(i = 0; i<total; i++) {
    DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,i,&user);
    if (user) {
      if (user->UIN == uin) {
        strcpy(nick,user->Nick);
        sprintf(mesg,"%ld %s",user->UIN,nick);
        set(app->TX_QuickTo,MUIA_Text_Contents,mesg);
        if (user->Status == STATUS_OFFLINE && (cmd == S_GET_MESSAGE || cmd == TCP_MESSAGE)) {
          user->Status = STATUS_ONLINE|STATUSF_INVISIBLE;
          if (user->UWin) {
            strcpy(user->UWin->Status,"Invisible");
            sprintf(user->UWin->Title,"%ld %s (%s)",user->UIN,user->Nick,user->UWin->Status);
            set(user->UWin->WI_UserWindow,MUIA_Window_Title,user->UWin->Title);
          }
          DoMethod(app->LV_OfflineList,MUIM_NList_Redraw,i);
          DoMethod(app->LV_OfflineList,MUIM_NList_Sort);
        }
        break;
      }
    }
  }
  if (i == total) {
    sprintf(mesg,"%ld",uin);
    set(app->TX_QuickTo,MUIA_Text_Contents,mesg);
  }
  set(app->WI_Message,MUIA_Window_ActiveObject,app->TI_QuickMsg);
}
else {
  get(app->LV_Msgs,MUIA_NList_Active,&total);
  set(app->LV_Msgs,MUIA_NList_Active,MUIV_NList_Active_Bottom);
  set(app->LV_Msgs,MUIA_NList_Active,total);
}

return;

}


void __asm GoURL(REG(a2) APTR obj)

{

char *txt = NULL, page[75];

LONG entry;

ULONG id = 0;

struct Contact *user;
struct ICQMessage *msg = NULL;

if (obj == app->BT_AdGoURL) get(app->TX_AdURL,MUIA_Text_Contents,&txt);

if (obj == app->TX_UserURL) get(app->TX_UserURL,MUIA_Text_Contents,&txt);

if (obj == app->LV_Msgs) {
  get(app->LV_Msgs,MUIA_NList_DoubleClick,&entry);
  if (entry < 0) return;
  DoMethod(app->LV_Msgs,MUIM_NList_GetEntry,entry,&msg);
  if (msg->Type != 0x0004) return;
  txt = (msg->Msg)+2;
}

if (!txt) {
  get(obj,MUIA_UserData,&id);
  if (id) {
    user = GetContact(id);
    if (obj == user->UWin->LV_Msgs) {
      get(user->UWin->LV_Msgs,MUIA_NList_DoubleClick,&entry);
      if (entry < 0) return;
      DoMethod(user->UWin->LV_Msgs,MUIM_NList_GetEntry,entry,&msg);
      if (msg->Type != 0x0004) return;
      txt = (msg->Msg)+2;
    }
    if (obj == user->UWin->BT_HomePage) get(user->UWin->BT_HomePage,MUIA_Text_Contents,&txt);
    if (obj == user->UWin->BT_WhitePage) {
      sprintf(page,"http://wwp.mirabilis.com/%ld/",id);
      txt = page;
    }
  }
}

if (!txt) return;

/*
if (!OpenURL) {
  get(app->STR_URLCmnd,MUIA_String_Contents,&urlcmd);
  if (!urlcmd || !txt) return;
  sprintf(gocmd,urlcmd,txt);
  System(gocmd,NULL);
}
else URL_Open(txt,TAG_DONE);
*/

if (OpenURL) URL_Open(txt,TAG_DONE);

return;

}


char *ParseMsgHdr(char *buf, struct Contact *user)

{

char *c, *p;

UBYTE auth;

p = buf;
c = strchr(p,'\376');
*c = '\0';

user->Nick = p;

p = c+1;
c = strchr(p,'\376');
*c = '\0';

user->First = p;

p = c+1;
c = strchr(p,'\376');
*c = '\0';

user->Last = p;

p = c+1;
c = strchr(p,'\376');
*c = '\0';

user->EMail = p;

p = c+1;

revmemcpy((char *)&auth,p,1);

user->Authorize = auth;

return(p++);

}


char *GetNick(ULONG uin)

{

BOOL flag = FALSE;

static char nick[100], *localnick;

int i;

ULONG total, localin;

struct Contact *user;

get(app->STR_ICQUIN,MUIA_String_Integer,&localin);
get(app->STR_Nick,MUIA_String_Contents,&localnick);

get(app->LV_OfflineList,MUIA_NList_Entries,&total);

for(i = 0; i<total; i++) {
  DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,i,&user);
  if (user) {
    if (user->UIN == uin) {
      strcpy(nick,user->Nick);
      flag = TRUE;
      break;
    }
  }
}
if (!flag) {
  if (uin == localin) {
    strcpy(nick,localnick);
  }
  else sprintf(nick,"%ld",uin);
}

return(nick);

}


void ContactsOffline(void)

{

int i;

ULONG total = 0;

struct Contact *user;

get(app->LV_OfflineList,MUIA_NList_Entries,&total);

for(i = 0; i<total; i++) {
  DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,i,&user);
  if (user) {
    if (user->Status != STATUS_NEWUIN) {
      user->Status = STATUS_OFFLINE;
      DoMethod(app->LV_OfflineList,MUIM_NList_Redraw,i);
      UpdateUserWin(user);
    }
  }
}
DoMethod(app->LV_OfflineList,MUIM_NList_Sort);

return;

}


BOOL OpenICQSocket(void)

{

char *host;

int i;

LONG size, total;

ULONG uin;

UWORD port;

struct Sockets Socks, *socks;

maxfd = -1;

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);
get(app->STR_TheServer,MUIA_String_Contents,&host);
get(app->STR_ThePort,MUIA_String_Integer,&size);

port = size;

#ifdef DEBUG
HandleError(DBG_UDP_DBUG,"%s:%d",host,port);
#endif

//if (!SocketBase) if (!(SocketBase = OpenLibrary("bsdsocket.library",4))) fail(NULL,"Could not open bsdsocket.library v4.");

if (FirstLogin) {
  if (SocketBaseTags(SBTM_SETREF(SBTC_SIGIOMASK),&PORT_mask,TAG_DONE) > 0) {
    HandleError(DBG_UDP_ERRS,"SocketBaseTags failed.");
    return(FALSE);
  }
  FD_ZERO(&rset);
  FD_ZERO(&wset);
}

FileListen = 0;

get(app->LV_SockList,MUIA_NList_Entries,&total);

for(i = total-1; i>-1; i--) {
  DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  if (socks) {
    if (socks->Type == SOCK_UDP || (socks->Dir == TCP_DIR_LISTEN && socks->Type != SOCK_CHAT)) DelSockets(socks->Socket);
  }
}

Socks.UIN = uin;
Socks.Dir = TCP_DIR_OUT;
Socks.TCPLen = Socks.Timehack = 0;
Socks.LastTCP = NULL;
Socks.ChatMode = Socks.FileMode = NULL;
Socks.RCObj = NULL;
Socks.Type = SOCK_UDP;
Socks.PktLen[0] = Socks.PktLen[1] = '\0';
Socks.Connecting = Socks.HadInit = Socks.Hidden = Socks.Backward = Socks.Closing = FALSE;
Socks.CWin = NULL;

memset((char *)&Socks.Address,0,sizeof(Socks.Address));

HandleError(DBG_UDP_DBUG,"Looking up ICQ server: %s",host);

if ((nameinfo = gethostbyname(host)) == NULL) {
  Socks.Address.sin_addr.s_addr = inet_addr(host);
  if ((int)Socks.Address.sin_addr.s_addr == -1) {
    HandleError(DBG_UDP_ERRS,"Your host '%s' was not found.",host);
    return(FALSE);
  }
}
else memcpy((char *)&Socks.Address.sin_addr.s_addr,nameinfo->h_addr,nameinfo->h_length);

HandleError(DBG_UDP_DBUG,"Found the host at %s",Inet_NtoA(Socks.Address.sin_addr.s_addr));

Socks.Address.sin_family = nameinfo->h_addrtype;
Socks.Address.sin_len = sizeof(struct sockaddr_in);

if (MiamiBase = OpenLibrary("miami.library",10)) {
  MiamiSetSocksConn((struct sockaddr *)&Socks.Address,sizeof(struct sockaddr_in));
  CloseLibrary(MiamiBase);
}

HandleError(DBG_UDP_DBUG,"Creating the UDP socket...");

if ((Socks.Socket = socket(nameinfo->h_addrtype,SOCK_DGRAM,0)) == -1) {
  HandleError(DBG_UDP_ERRS,"Could not open Mirabilis socket.");
  return(FALSE);
}

HandleError(DBG_UDP_DBUG,"Opened the UDP connection as socket %d",Socks.Socket);

if (Socks.Socket > maxfd) maxfd = Socks.Socket;

FD_SET(Socks.Socket,&rset);

Socks.Address.sin_port = htons(port);

Socks.IP = Socks.Address.sin_addr.s_addr;
Socks.Port = Socks.Address.sin_port;

HandleError(DBG_UDP_DBUG,"Making UDP socket asynchronous");

if (IoctlSocket(Socks.Socket,FIOASYNC,(char *)&size) == -1) {
  HandleError(DBG_UDP_ERRS,"Error in IoctlSocket FIOASYNC for UDP socket.");
  return(FALSE);
}

HandleError(DBG_UDP_DBUG,"Making UDP socket non-blocking");

if (IoctlSocket(Socks.Socket,FIONBIO,(char *)&size) == -1) {
  HandleError(DBG_UDP_ERRS,"Error in IoctlSocket FIONBIO for UDP socket.");
  return(FALSE);
}

/*
if (bind(Socks.Socket,(struct sockaddr *)&Socks.Address,sizeof(struct sockaddr_in)) == -1) {
  HandleError(DBG_UDP_ERRS,"Could not bind the UDP socket.");
}
*/

/*
if (connect(sock,(struct sockaddr *)&server,sizeof(server)) == -1) {
  if (Errno() != EINPROGRESS) {
    HandleError(DBG_UDP_ERRS,"Could not connect on UDP socket.");
    return(FALSE);
  }
}
*/

DoMethod(app->LV_SockList,MUIM_NList_InsertSingle,&Socks,MUIV_NList_Insert_Sorted);

HandleError(DBG_UDP_DBUG,"UDP socket is established");

// Finished with the UDP socket(s), now for the TCP socket(s)

if (!OpenTCPListen(SOCK_MESSAGE)) return(FALSE);

get(app->LV_SockList,MUIA_NList_Entries,&total);

if (total > 0) {
  DoMethod(app->LV_SockList,MUIM_NList_GetEntry,total-1,&socks);
  if (socks->Socket > maxfd) maxfd = socks->Socket;
}

return(TRUE);

}


ULONG OpenTCPListen(UBYTE type)

{

BOOL *hideip;

char host[128];

LONG size;

ULONG uin;

struct Sockets Socks;

host[0] = '\0';

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);
get(app->CH_HideIP,MUIA_Selected,&hideip);

gethostname(host,sizeof(host));

Socks.UIN = uin;
Socks.Dir = TCP_DIR_LISTEN;
Socks.TCPLen = Socks.Timehack = 0;
Socks.LastTCP = NULL;
Socks.ChatMode = Socks.FileMode = NULL;
Socks.CWin = NULL;
Socks.RCObj = NULL;
Socks.Connecting = Socks.HadInit = Socks.Backward = Socks.Closing = FALSE;
Socks.Hidden = hideip?TRUE:FALSE;
Socks.Type = type;
Socks.CWin = NULL;
Socks.PktLen[0] = Socks.PktLen[1] = '\0';

if ((Socks.Socket = socket(AF_INET,SOCK_STREAM,0)) == -1) {
  HandleError(DBG_TCP_ERRS,"Could not open TCP socket.");
  return(FALSE);
}

FD_SET(Socks.Socket,&rset);

size = 1;

memset((char *)&Socks.Address,0,sizeof(Socks.Address));

Socks.Address.sin_family = AF_INET;
Socks.Address.sin_addr.s_addr = htonl(INADDR_ANY);
Socks.Address.sin_port = htons(0);
Socks.Address.sin_len = sizeof(struct sockaddr_in);

if (bind(Socks.Socket,(struct sockaddr *)&Socks.Address,sizeof(Socks.Address)) == -1) {
  HandleError(DBG_TCP_ERRS,"Could not bind TCP socket.");
//return(FALSE);
}

if (listen(Socks.Socket,5) == -1) {
  HandleError(DBG_TCP_ERRS,"Could not listen to TCP socket.");
  return(FALSE);
}

size = sizeof(Socks.Address);

if (getsockname(Socks.Socket,(struct sockaddr *)&Socks.Address,&size) == -1) {
  HandleError(DBG_TCP_ERRS,"Error in getsockname while opening a listening socket.");
  return(FALSE);
}

Socks.Port = Socks.ConnectPort = Socks.Address.sin_port;

memset((char *)&Socks.Address,0,sizeof(Socks.Address));

if ((nameinfo = gethostbyname(host)) == NULL) {
  Socks.Address.sin_addr.s_addr = inet_addr(host);
  if ((int)Socks.Address.sin_addr.s_addr == -1) {
    HandleError(DBG_TCP_ERRS,"Your LOCAL host name '%s' could not be resolved.",host);
  }
}
else memcpy((char *)&Socks.Address.sin_addr.s_addr,nameinfo->h_addr_list[0],nameinfo->h_length);

Socks.IP = Socks.Address.sin_addr.s_addr;

size = 1;

if (IoctlSocket(Socks.Socket,FIOASYNC,(char *)&size) == -1) {
  HandleError(DBG_TCP_ERRS,"Error in IoctlSocket FIOASYNC for TCP socket.");
  return(FALSE);
}

if (IoctlSocket(Socks.Socket,FIONBIO,(char *)&size) == -1) {
  HandleError(DBG_TCP_ERRS,"Error in IoctlSocket FIONBIO for TCP socket.");
  return(FALSE);
}

if (Socks.Socket > maxfd) maxfd = Socks.Socket;

DoMethod(app->LV_SockList,MUIM_NList_InsertSingle,&Socks,MUIV_NList_Insert_Sorted);

return(Socks.Port);

}


void __asm AddServer(REG(a2) APTR obj)

{

char *server, *port, *line_p, line[100], *c;

ULONG entry;

if (obj == app->BT_AddServer) {
  get(app->STR_TheServer,MUIA_String_Contents,&server);
  get(app->STR_ThePort,MUIA_String_Contents,&port);
  sprintf(line,"%s:%s",server,port);
  DoMethod(app->LV_ICQServers,MUIM_NList_InsertSingle,line,MUIV_NList_Insert_Sorted);
}
else {
  get(app->LV_ICQServers,MUIA_NList_EntryClick,&entry);
  if (entry < 0) return;
  DoMethod(app->LV_ICQServers,MUIM_NList_GetEntry,entry,&line_p);
  strcpy(line,line_p);
  server = line;
  c = strchr(line,':');
  *c = '\0';
  port = c+1;
  set(app->STR_TheServer,MUIA_String_Contents,server);
  set(app->STR_ThePort,MUIA_String_Contents,port);
}

return;

}


void StoreMessage(struct ICQMessage *msg, ULONG uinwin, UWORD cmd)

{

BOOL *auto_ch, *winopen;

char uinlog[MAXNAMLEN], *notifycmd, cmdln[MAXNAMLEN];

int i;

LONG lamp;

ULONG uin = 0, total = 0;

struct AsyncFile *logfh;

struct Contact *user;

if (strlen(msg->Msg) && msg->Type != 0x04) {
  get(app->STR_MsgNotify,MUIA_String_Contents,&notifycmd);
  if (notifycmd) {
    if (strlen(notifycmd) > 0) {
      sprintf(cmdln,notifycmd,uinwin);
      System(cmdln,NULL);
    }
  }
  else DisplayBeep(NULL);
}

DoMethod(app->LV_Msgs,MUIM_NList_InsertSingleWrap,msg,MUIV_NList_Insert_Bottom,WRAPCOL2,ALIGN_LEFT);
DoMethod(app->LV_Msgs,MUIM_NList_Jump,MUIV_NList_Jump_Bottom);

get(app->LV_OfflineList,MUIA_NList_Entries,&total);

for(i = 0; i < total; i++) {
  DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,i,&user);
  if (user) if (user->UIN == uinwin) {
    if (!user->UWin) if (!CreateUserWin(uinwin)) break;
    if (msg->Type == 0x04) {
      uin = msg->UIN;
      msg->UIN = 0;
    }
    DoMethod(user->UWin->LV_Msgs,MUIM_NList_InsertSingleWrap,msg,MUIV_NList_Insert_Bottom,WRAPCOL2,ALIGN_LEFT);
    DoMethod(user->UWin->LV_Msgs,MUIM_NList_Jump,MUIV_NList_Jump_Bottom);
    if (msg->Type == 0x04) msg->UIN = uin;
    if (!strlen(msg->Msg)) break;
    get(app->CH_Scrn2Frnt,MUIA_Selected,&auto_ch);
    if (auto_ch) DoMethod(app->WI_Main,MUIM_Window_ScreenToFront);
    get(app->CH_MsgPopup,MUIA_Selected,&auto_ch);
    if (auto_ch) {
      get(user->UWin->WI_UserWindow,MUIA_Window_Open,&winopen);
      if (!winopen) set(user->UWin->WI_UserWindow,MUIA_Window_Open,TRUE);
      else DoMethod(user->UWin->WI_UserWindow,MUIM_Window_ToFront);
    }
    else {
      get(user->UWin->WI_UserWindow,MUIA_Window_Open,&winopen);
      get(app->WI_Message,MUIA_Window_Open,&auto_ch);
      if (!winopen && !auto_ch && msg->Type != 0x04) {
        switch(++user->NewMsg) {
          case 1:
            if (WhichLamp == 0) lamp = MUIV_Lamp_Color_Ok;
            else lamp = MUIV_TWFmultiLED_Colour_On;
            break;
          case 2:
            if (WhichLamp == 0) lamp = MUIV_Lamp_Color_Warning;
            else lamp = MUIV_TWFmultiLED_Colour_Ok;
            break;
          case 3:
            if (WhichLamp == 0) lamp = MUIV_Lamp_Color_Error;
            else lamp = MUIV_TWFmultiLED_Colour_Load;
            break;
          default:
            if (WhichLamp == 0) lamp = MUIV_Lamp_Color_FatalError;
            else lamp = MUIV_TWFmultiLED_Colour_Error;
        }
        if (WhichLamp == 0) set(user->LampObj,MUIA_Lamp_Color,lamp);
        else set(user->LampObj,MUIA_TWFmultiLED_Colour,lamp);
//      DoMethod(app->LV_OfflineList,MUIM_NList_Redraw,MUIV_NList_Redraw_All);
        DoMethod(app->LV_OfflineList,MUIM_NList_Redraw,i);
        DoMethod(app->LV_OfflineList,MUIM_NList_Sort);
      }
    }
    break;
  }
}

get(app->CH_NoMsgLog,MUIA_Selected,&auto_ch);

if (auto_ch) return;

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);

sprintf(uinlog,"%sUsers/%ld/Logs/%ld",currentdir,uin,msg->UIN);

if (logfh = OpenAsync(uinlog,MODE_APPEND,AsyncBuf)) {
  if (msg->Type == 0x04) SeekAsync(logfh,-1,MODE_CURRENT);
  if (msg->Timehack) {
    WriteLineAsync(logfh,ctime(&msg->Timehack));
  }
  WriteLineAsync(logfh,"R: ");
  WriteLineAsync(logfh,msg->Msg);
  WriteLineAsync(logfh,"\n\n");
  CloseAsync(logfh);
  SetComment(uinlog,GetNick(msg->UIN));
}

return;

}


void __asm ViewHistory(REG(a2) APTR obj)

{

char uinlog[MAXNAMLEN], line[1024], info[100], *path;

ULONG uin = 0, localin = 0;

struct AsyncFile *loadfh;

if (obj == app->WI_MessageHist) {
  set(app->DL_MsgDir,MUIA_Dirlist_Directory,logdir_fl);
  get(app->STR_ICQUIN,MUIA_String_Integer,&localin);
}
else {
  get(app->DL_MsgDir,MUIA_Dirlist_Path,&path);
  if (!strlen(path)) return;
  StrToLong(FilePart(path),(LONG *)&localin);
}

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);

DoMethod(app->LV_MsgText,MUIM_NList_Clear);

sprintf(uinlog,"%sUsers/%ld/Logs/%ld",currentdir,uin,localin);

set(app->LV_MsgText,MUIA_NList_Quiet,TRUE);

if (loadfh = OpenAsync(uinlog,MODE_READ,AsyncBuf)) {
  sprintf(info,"%ld %s",localin,GetNick(localin));
  set(app->TX_MsgUser,MUIA_Text_Contents,info);
  while(ReadLineAsync(loadfh,line,sizeof(line)) > 0) {
    LASTCHAR(line) = '\0';
    DoMethod(app->LV_MsgText,MUIM_NList_InsertWrap,line,-2,MUIV_NList_Insert_Bottom,WRAPCOL0,ALIGN_LEFT);
  }
  CloseAsync(loadfh);
}
else set(app->TX_MsgUser,MUIA_Text_Contents,"Not Found");

set(app->LV_MsgText,MUIA_NList_Quiet,FALSE);

set(app->WI_MessageHist,MUIA_Window_Open,TRUE);

return;

}


void __asm SendUInfo1(REG(a2) APTR obj)

{

char *nick, *first, *last, *email;

int len;

UBYTE auth;

ULONG uin, reqauth;

UWORD cmd;

struct C_Update_Basic_Info basic;
struct C_UpdateAuth Auth;

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);
get(app->STR_Nick,MUIA_String_Contents,&nick);
get(app->STR_First,MUIA_String_Contents,&first);
get(app->STR_Last,MUIA_String_Contents,&last);
get(app->STR_EMail,MUIA_String_Contents,&email);
get(app->RD_ReqAuth,MUIA_Radio_Active,&reqauth);

if (reqauth) auth = 0x00;
else auth = 0x01;

if (obj == app->BT_UpUInfo1) cmd = C_UPDATE_INFO;
else cmd = C_NEW_USER_INFO;

Header.Command = cmd;

basic.Sequence = chguinfo_seq++;

strcpy(basic.Nick,nick);
strcpy(basic.First,first);
strcpy(basic.Last,last);
strcpy(basic.EMail,email);

basic.Authorize = -auth+1;

len = UDP_CreatePacket(&Header,&basic,UDP_Buf);

send_udp_pkt(UDP_Buf,len,uin);

Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);

if (!NewUser) {
  Header.Command = C_UPDATE_AUTH;
  Auth.Sequence = chguinfo_seq++;
  Auth.Authorize = auth;
  len = UDP_CreatePacket(&Header,&Auth,UDP_Buf);
  send_udp_pkt(UDP_Buf,len,uin);
  Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
}

return;

}


void __asm SendUInfo2(REG(a2) APTR obj)

{

BYTE status;

char *city, *state, *phone, *url, *about, about2[512], *c, *d;

int len;

LONG zone;

UBYTE sex;

ULONG uin, country1, age1, sex1;

UWORD country, age;

struct C_Update_Ext_Info Ext;

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);
get(app->STR_City,MUIA_String_Contents,&city);
get(app->STR_State,MUIA_String_Contents,&state);
get(app->STR_Phone,MUIA_String_Contents,&phone);
get(app->STR_Page,MUIA_String_Contents,&url);
get(app->TI_About,MUIA_Textinput_Contents,&about);
get(app->STR_Country,MUIA_String_Integer,&country1);
get(app->NU_TimeZone,MUIA_Numeric_Value,&zone);
get(app->STR_Age,MUIA_String_Integer,&age1);
get(app->CY_Sex,MUIA_Cycle_Active,&sex1);

country = country1;
age = age1;
sex = sex1;

if (country == 0) country = 0xffff;

status = -(zone*2);

if (age == 0) age = 0xffff;

Header.Command = C_UPDATE_EXT_INFO;

Ext.Sequence = chguinfo_seq++;
Ext.Country = country;
Ext.Timezone = status;
Ext.Age = age;
Ext.Sex = sex;

for(c = about, d = about2; *c; c++, d++) {
  if (*c == '\n') *d++ = '\r';
  *d = *c;
}
*d = '\0';

strcpy(Ext.City,city);
strcpy(Ext.State,state);
strcpy(Ext.Phone,phone);
strcpy(Ext.URL,url);
strcpy(Ext.About,about2);

len = UDP_CreatePacket(&Header,&Ext,UDP_Buf);

send_udp_pkt(UDP_Buf,len,uin);

Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);

return;

}


void __asm NewUIN(REG(a2) APTR obj)

{

char *pw;

int len;

if (!MUI_Request(app->App,app->WI_Main,0,NULL,"Continue|Cancel","\033cPress Continue only after\nyou have filled in all\nthe information on the\n ICQ Basic and Extended Prefs pages\nin the Prefs window\nexcept for User ID Number.")) return;

get(app->STR_ICQPass,MUIA_String_Contents,&pw);

if (!strlen(pw)) {
  HandleError(DBG_OTH_FATL,"You need to at least specify a Password!");
  return;
}

if (Online) DisconnectICQ(NULL);

FirstLogin = NewUser = TRUE;

set(app->TX_Color,MUIA_Text_Contents,"Creating New UIN");

if (!(SocketOpen = OpenICQSocket())) {
  HandleError(DBG_OTH_FATL,"Could not connect to ICQ.");
  return;
}

Header.Command = C_NEW_USER_1;
Header.UIN = 0;

len = UDP_CreatePacket(&Header,NULL,UDP_Buf);

send_udp_pkt(UDP_Buf,len,0x00000000);

DoMethod(app->LV_ICQCliLog,MUIM_NList_Clear);
DoMethod(app->LV_ICQSrvLog,MUIM_NList_Clear);

Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);

return;

}


void __asm MakeFilenames(REG(a2) APTR obj)

{

ULONG uin = 0;

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);

sprintf(contact_fl,"%sUsers/%ld/Contacts",currentdir,uin);
sprintf(config_fl,"%sUsers/%ld/STRICQ.cfg",currentdir,uin);
sprintf(colors_fl,"%sUsers/%ld/Config.cfg",currentdir,uin);
sprintf(server_fl,"%sUsers/%ld/Servers.cfg",currentdir,uin);
sprintf(logdir_fl,"%sUsers/%ld/Logs/",currentdir,uin);
sprintf(userdir_fl,"%sUsers/%ld/Users/",currentdir,uin);

return;

}


APTR __asm AddActy(REG(a2) APTR pool, REG(a1) struct Activity *acty)

{

struct Activity *newacty = NULL;

if (!(newacty = AllocPooled(pool,sizeof(struct Activity)))) return(NULL);

newacty->UIN = acty->UIN;
newacty->Status = acty->Status;
newacty->Timehack = acty->Timehack;

return(newacty);

}


void __asm RemActy(REG(a2) APTR pool, REG(a1) struct Activity *newacty)

{

FreePooled(pool,newacty,sizeof(struct Activity));

return;

}


LONG __asm CmpActy(REG(a1) struct Activity *a1, REG(a2) struct Activity *a2)

{

BOOL *auto_ch;

struct Contact *u1, *u2;

get(app->CH_ActySort,MUIA_Selected,&auto_ch);

if (!auto_ch) {
  if (a1->Timehack < a2->Timehack) return(-1);
  if (a1->Timehack > a2->Timehack) return(1);
  return(0);
}

u1 = GetContact(a1->UIN);
u2 = GetContact(a2->UIN);

if (stricmp(u1->Nick,u2->Nick) == 0) {
  if (a1->Timehack < a2->Timehack) return(-1);
  else return(1);
}

return(stricmp(u1->Nick,u2->Nick));

}


void __asm DisplayActy(REG(a2) char **array, REG(a1) struct Activity *acty)

{

BOOL *usebeats;

static char nick[100], tmp[15], tme[20], status[30];

struct ColorText *ct;

ULONG pen = 2;

get(app->CH_UseBeats,MUIA_Selected,&usebeats);

if (acty) {
  ct = GetStatus(acty->Status);
  pen = MUIPEN(ct->Pen);
  sprintf(status,"\033P[%ld]%s",pen,ct->Status);
  if (usebeats) sprintf(tmp,"@ %d",MakeBeats(acty->Timehack));
  else strncpy(tmp,ctime(&acty->Timehack)+11,8);
  sprintf(tme,"\033P[%ld]%s",pen,tmp);
  sprintf(nick,"\033P[%ld]%s",pen,GetNick(acty->UIN));
  *array++ = nick;
  *array++ = tme;
  *array   = status;
}
else {
  *array++ = "Nick";
  *array++ = "Time";
  *array   = "Activity";
}

return;

}


void __asm LoadPrefs(REG(a2) APTR obj)

{

BPTR mylock;

char line[1024], first[50], last[50];

int i;

ULONG uin;

UWORD length = 0;

__aligned struct FileInfoBlock *myFIB;

struct AsyncFile  *loadfh;
struct Column      Col;
struct Contact     User;
struct IgnoreUIN   Ignore;
struct MUI_PenSpec startpen;

PrepNewContact(&User);
MakeFilenames(NULL);

MyCreateDir(logdir_fl);
MyCreateDir(userdir_fl);

line[0] = '\0';

set(app->GA_Contacts,MUIA_Gauge_InfoText,"Loading Application");

DoMethod(app->App,MUIM_Application_Load,config_fl);

set(app->GA_Contacts,MUIA_Gauge_InfoText,"Loading Pens & About");

if (loadfh = OpenAsync(colors_fl,MODE_READ,AsyncBuf)) {
  for(i = 0; i < 8; i++) {
    ReadAsync(loadfh,&startpen,sizeof(struct MUI_PenSpec));
    set(app->PP_StatusColors[i],MUIA_Pendisplay_Spec,&startpen);
  }
  ReadAsync(loadfh,&URLMsg_cnt,sizeof(URLMsg_cnt));
  ReadAsync(loadfh,&length,sizeof(length));
  ReadAsync(loadfh,line,length);
  set(app->TI_About,MUIA_Textinput_Contents,line);
  ReadAsync(loadfh,&SrvrMsg_cnt,sizeof(SrvrMsg_cnt));
  for(i = 8; i < NUM_STATUS_COLORS; i++) {
    if (ReadAsync(loadfh,&startpen,sizeof(struct MUI_PenSpec))) set(app->PP_StatusColors[i],MUIA_Pendisplay_Spec,&startpen);
  }
  for(i = 0; i < NUM_CHAT_COLORS; i++) {
    if (ReadAsync(loadfh,&startpen,sizeof(struct MUI_PenSpec))) set(app->PP_ChatColors[i],MUIA_Pendisplay_Spec,&startpen);
  }
  CloseAsync(loadfh);
}

DoMethod(app->App,MUIM_Application_InputBuffered);

DoMethod(app->LV_OfflineList,MUIM_NList_Clear);

set(app->LV_OfflineList,MUIA_NList_Quiet,TRUE);

contacts_cnt = 0;

get(app->CY_Lamp,MUIA_Cycle_Active,&WhichLamp);

// TX_LoadProgress,MUIA__Contents
set(app->GA_Contacts,MUIA_Gauge_InfoText,"Loading Contacts");

if (!(myFIB = (struct FileInfoBlock *)AllocVec(sizeof(struct FileInfoBlock),MEMF_PUBLIC|MEMF_CLEAR))) {
  HandleError(DBG_OTH_FATL,"Could not allocate FileInfoBlock.  Out of memory.");
  return;
}

if ((mylock = Lock(userdir_fl,SHARED_LOCK)) == NULL) {
  HandleError(DBG_OTH_FATL,"Could not Lock '%s' to read dir.",userdir_fl);
  FreeVec(myFIB);
  return;
}

if (Examine(mylock,myFIB) == NULL) {
  HandleError(DBG_OTH_FATL,"Could not Examine '%s' to count dir.",userdir_fl);
  FreeVec(myFIB);
  UnLock(mylock);
  return;
}

while(ExNext(mylock,myFIB) != NULL) contacts_cnt++;

set(app->GA_Contacts,MUIA_Gauge_Current,0);
set(app->GA_Contacts,MUIA_Gauge_Max,contacts_cnt);

contacts_cnt = 0;

if (Examine(mylock,myFIB) == NULL) {
  HandleError(DBG_OTH_FATL,"Could not Examine '%s' to read dir.",userdir_fl);
  FreeVec(myFIB);
  UnLock(mylock);
  return;
}

while(ExNext(mylock,myFIB) != NULL) {
  sscanf(myFIB->fib_FileName,"%ld",&uin);
  LoadContact(uin);
  DoMethod(app->App,MUIM_Application_InputBuffered);
  contacts_cnt++;
  set(app->GA_Contacts,MUIA_Gauge_Current,contacts_cnt);
}

UnLock(mylock);
FreeVec(myFIB);

set(app->GA_Contacts,MUIA_Gauge_InfoText,"Sorting Contacts");

DoMethod(app->LV_OfflineList,MUIM_NList_Sort);

set(app->LV_OfflineList,MUIA_NList_Quiet,FALSE);

set(app->GA_Contacts,MUIA_Gauge_InfoText,"Servers, Columns, Ignore");

DoMethod(app->LV_ICQServers,MUIM_NList_Clear);
DoMethod(app->LV_ColsStore,MUIM_NList_Clear);
DoMethod(app->LV_ColsUse,MUIM_NList_Clear);
DoMethod(app->LV_IgnoreUIN,MUIM_NList_Clear);

if (loadfh = OpenAsync(server_fl,MODE_READ,AsyncBuf)) {
  while(ReadLineAsync(loadfh,line,sizeof(line)) > 0) {
    if (line[0] == ';') break;
    LASTCHAR(line) = '\0';
    DoMethod(app->LV_ICQServers,MUIM_NList_InsertSingle,line,MUIV_NList_Insert_Sorted);
  }
  while(ReadLineAsync(loadfh,first,sizeof(first)) > 0) {
    if (first[0] == ';') break;
    LASTCHAR(first) = '\0';
    ReadLineAsync(loadfh,last,sizeof(last));
    LASTCHAR(last) = '\0';
    Col.Name = first;
    Col.COL = last;
    DoMethod(app->LV_ColsStore,MUIM_NList_InsertSingle,&Col,MUIV_NList_Insert_Bottom);
  }
  while(ReadLineAsync(loadfh,first,sizeof(first)) > 0) {
    if (first[0] == ';') break;
    LASTCHAR(first) = '\0';
    ReadLineAsync(loadfh,last,sizeof(last));
    LASTCHAR(last) = '\0';
    Col.Name = first;
    Col.COL = last;
    DoMethod(app->LV_ColsUse,MUIM_NList_InsertSingle,&Col,MUIV_NList_Insert_Bottom);
  }
  while(ReadLineAsync(loadfh,line,sizeof(line)) > 0) {
    if (line[0] == ';') break;
    StrToLong(line,(LONG *)&Ignore.UIN);
    ReadLineAsync(loadfh,line,sizeof(line));
    LASTCHAR(line) = '\0';
    strcpy(Ignore.Nick,line);
    ReadLineAsync(loadfh,line,sizeof(line));
    StrToLong(line,(LONG *)&Ignore.Timehack);
    ReadLineAsync(loadfh,line,sizeof(line));
    StrToLong(line,(LONG *)&uin);
    Ignore.ExpireDays = uin;
    if (time(NULL) < Ignore.ExpireDays && Ignore.ExpireDays > 0) DoMethod(app->LV_IgnoreUIN,MUIM_NList_InsertSingle,&Ignore,MUIV_NList_Insert_Bottom);
  }
  CloseAsync(loadfh);
}

DoMethod(app->App,MUIM_Application_InputBuffered);

DoMethod(app->LV_Activity,MUIM_NList_Clear);

sprintf(maintitle,"STRICQ (%d)",contacts_cnt);
set(app->WI_Main,MUIA_Window_Title,maintitle);

return;

}


BOOL MyCreateDir(char *dir)

{

BPTR mylock;

char *s;

s = dir;

while (s = strchr(s+1,'/')) {
  *s = '\0';
  if (mylock = Lock(dir,ACCESS_READ)) {
    UnLock(mylock);
    *s = '/';
    continue;
  }
  if (mylock = CreateDir(dir)) UnLock(mylock);
  else {
    HandleError(DBG_OTH_INFO,"Could not create directory:  %s",dir);
    return(FALSE);
  }
  *s = '/';
}

return(TRUE);

}


void __asm ChangeMyUIN(REG(a2) APTR obj)

{

BOOL tmponline;

char *entry;

get(app->DL_UINList,MUIA_Dirlist_Path,&entry);

tmponline = Online;

DisconnectICQ(NULL);

SavePrefs(NULL);

set(app->STR_ICQUIN,MUIA_String_Contents,FilePart(entry));

get(app->STR_ICQUIN,MUIA_String_Integer,&Header.UIN);

LoadPrefs(NULL);

if (tmponline) ConnectICQ(NULL);

return;

}


void __asm SaveMsgWin(REG(a2) APTR obj)

{

char save_fl[MAXNAMLEN], line[1024];

char title[] = "Save Current Messages:";

int i;

time_t newhack, lasthack = 0;

ULONG entries;

struct AsyncFile     *savefh;
struct ICQMessage    *msg;
struct FileRequester *myasl;
struct Window        *mywin = NULL;

struct TagItem MyASLTags[] = {
  {ASLFR_TitleText,    NULL},
  {ASLFR_Window,       NULL},
  {ASLFR_InitialDrawer,NULL},
  {ASLFR_DoSaveMode,   TRUE},
  {ASLFR_RejectIcons,  TRUE},

  {TAG_DONE,NULL},
};

get(app->LV_Msgs,MUIA_NList_Entries,&entries);
get(app->WI_Main,MUIA_Window_Window,&mywin);

MyASLTags[0].ti_Data = (ULONG)title;
MyASLTags[1].ti_Data = (ULONG)mywin;
MyASLTags[2].ti_Data = (ULONG)currentdir;

if (entries < 1) return;

if (!(myasl = MUI_AllocAslRequest(ASL_FileRequest,MyASLTags))) return;

if (!MUI_AslRequest(myasl,NULL)) return;

if (LASTCHAR(myasl->fr_Drawer) != ':' && LASTCHAR(myasl->fr_Drawer) != '/') sprintf(save_fl,"%s/%s",myasl->fr_Drawer,myasl->fr_File);
else sprintf(save_fl,"%s%s",myasl->fr_Drawer,myasl->fr_File);

MUI_FreeAslRequest(myasl);

if (!(savefh = OpenAsync(save_fl,MODE_WRITE,AsyncBuf))) {
  HandleError(DBG_OTH_INFO,"Could not open the save file:  %s",save_fl);
  return;
}

for(i = 0; i < entries; i++) {
  DoMethod(app->LV_Msgs,MUIM_NList_GetEntry,i,&msg);
  if (msg) {
    if (msg->Type == 0) {
      WriteCharAsync(savefh,'\n');
      continue;
    }
    newhack = msg->Timehack;
    if (newhack == lasthack) continue;
    line[0] = '\0';
    if (msg->UIN != 0) sprintf(line,"%s %.8s ",GetNick(msg->UIN),ctime(&msg->Timehack)+11);
    if (msg->Type != 0x0004) strcat(line,msg->Msg);
    else strcat(line,msg->Msg+2);
    WriteLineAsync(savefh,line);
    WriteCharAsync(savefh,'\n');
    lasthack = newhack;
  }
}

CloseAsync(savefh);

return;

}


void __asm NewUserWin(REG(a2) APTR obj)

{

BOOL *openwin, flag = TRUE;

LONG entry;

struct Contact *user;

get(app->LV_OfflineList,MUIA_NList_DoubleClick,&entry);

if (entry < 0) return;

DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,entry,&user);

if (!user) return;

if (user->NewMsg) {
  user->NewMsg = 0;
  user->Changed = TRUE;
  if (WhichLamp == 0) set(user->LampObj,MUIA_Lamp_Color,MUIV_Lamp_Color_Off);
  else set(user->LampObj,MUIA_TWFmultiLED_Colour,MUIV_TWFmultiLED_Colour_Off);
  DoMethod(app->LV_OfflineList,MUIM_NList_Redraw,entry);
  DoMethod(app->LV_OfflineList,MUIM_NList_Sort);
}

if (!user->UWin) flag = CreateUserWin(user->UIN);

get(user->UWin->WI_UserWindow,MUIA_Window_Open,&openwin);

if (!openwin && flag) set(user->UWin->WI_UserWindow,MUIA_Window_Open,TRUE);
if (openwin && flag) DoMethod(user->UWin->WI_UserWindow,MUIM_Window_ToFront);

return;

}


BOOL CreateUserWin(ULONG id)

{

BOOL *multiline, *usetime;

struct Contact *user = NULL;

struct UserWindow *UWin;

if (!(user = GetContact(id))) return(FALSE);

if (!(UWin = AllocVec(sizeof(struct UserWindow),MEMF_CLEAR))) {
  HandleError(DBG_OTH_FATL,"Failed to AllocVec %d bytes!",sizeof(struct UserWindow));
  return(FALSE);
}

get(app->CH_MsgTime,MUIA_Selected,&usetime);
get(app->CH_MultiLine,MUIA_Selected,&multiline);

UWin->DoNotDelete = FALSE;

UWin->SC_AboutScroll   = ScrollbarObject, End;
UWin->SC_CommentScroll = ScrollbarObject, End;

UWin->WI_UserWindow = WindowObject,
  MUIA_Window_Title, UWin->Title,
  MUIA_Window_ID, id,
  MUIA_Window_Activate, FALSE,
  MUIA_UserData, id,
  WindowContents, GroupObject,
    Child, UWin->RG_UserPages = RegisterObject,
      MUIA_Register_Titles, UPages,
      MUIA_CycleChain, TRUE,
      Child, VGroup,
        Child, VGroup,
          Child, UWin->LV_Msgs = NListviewObject,
            MUIA_CycleChain, 1,
            MUIA_NListview_NList, NListObject,
              MUIA_Frame, MUIV_Frame_String,
              MUIA_NList_Title, TRUE,
              MUIA_NList_Format, "BAR,BAR,",
//            MUIA_NList_TypeSelect, MUIV_NList_TypeSelect_Char,
              MUIA_NList_CompareHook, &CmpMsgHook,
              MUIA_NList_ConstructHook, &AddMsgHook,
              MUIA_NList_DestructHook, &RemMsgHook,
              MUIA_NList_DisplayHook, &DisplayMsgHook,
              MUIA_ShortHelp, "Double-Click an underlined URL to\nopen the link in a browser.  Click on\nthe URL, not description, to Forward\nthe URL message.",
            End,
          End,
        End,
        Child, BalanceObject, End,
        Child, HGroup,
          Child, UWin->TI_QuickMsg = TextinputObject,
            MUIA_Frame, MUIV_Frame_String,
            MUIA_CycleChain, 1,
            MUIA_UserData, id,
            MUIA_Textinput_Multiline, multiline,
            MUIA_Textinput_Contents, NULL,
            MUIA_Textinput_MaxLen, 450,
            MUIA_Textinput_RemainActive, TRUE,
            MUIA_ShortHelp, "To send a message, type it\nhere and press RETURN to send.",
          End,
          Child, VGroup,
            MUIA_Weight, 40,
            Child, HGroup,
              Child, UWin->BT_SendIt = TextObject,
                MUIA_Frame, MUIV_Frame_Button,
                MUIA_Font, MUIV_Font_Button,
                MUIA_Text_Contents, "Send",
                MUIA_Text_PreParse, "\33c",
                MUIA_InputMode, MUIV_InputMode_RelVerify,
                MUIA_Background, MUII_ButtonBack,
                MUIA_ShortHelp, "Click here to send a multi-line message.\nUse TAB then ENTER for keyboard control.",
                MUIA_Weight, 0,
                MUIA_CycleChain, 1,
                MUIA_UserData, id,
              End,
              Child, UWin->BB_WaitTCP = BusyObject,
                MUIA_Busy_Speed, MUIV_Busy_Speed_Off,
              End,
              Child, UWin->CH_MultiSend = ImageObject,
                MUIA_Frame, MUIV_Frame_ImageButton,
                MUIA_InputMode, MUIV_InputMode_Toggle,
                MUIA_Image_Spec, MUII_CheckMark,
                MUIA_Image_FreeVert, TRUE,
                MUIA_Selected, FALSE,
                MUIA_Background, MUII_ButtonBack,
                MUIA_ShowSelState, FALSE,
                MUIA_CycleChain, 1,
                MUIA_ShortHelp, "Tick this gadget to also send a message to\nall selected contacts in the contact list",
              End,
              Child, UWin->POP_Choices = PopobjectObject,
                MUIA_Popstring_Button, PopButton(MUII_PopUp),
                MUIA_CycleChain, 1,
                MUIA_ShortHelp, "Commands that act\non this UIN.",
                MUIA_Popobject_Object, GroupObject,
                  MUIA_Group_Spacing, 0,
                  MUIA_Frame, MUIV_Frame_String,
                  Child, UWin->BT_Auth = SimpleButton("Authorize"),
                  Child, UWin->BT_ChatReq = SimpleButton("Chat"),
                  Child, UWin->BT_Clear = SimpleButton("Clear Messages"),
                  Child, UWin->BT_FileSend = SimpleButton("FileDirect"),
                  Child, UWin->BT_Forward = SimpleButton("Forward"),
                  Child, UWin->BT_IgnoreMe = SimpleButton("Ignore"),
                  Child, UWin->BT_Contacts = SimpleButton("Send Contacts"),
                  Child, UWin->BT_WhitePage = SimpleButton("WhitePage"),
                End,
              End,
            End,
            Child, HVSpace,
          End,
        End,
      End,
      Child, VGroup,
        Child, HGroup,
          MUIA_Group_Columns, 2,
          Child, Label("Description"),
          Child, UWin->STR_Desc = TextinputObject,
            MUIA_Frame, MUIV_Frame_String,
            MUIA_Textinput_Multiline, FALSE,
            MUIA_Textinput_MaxLen, 450,
            MUIA_Textinput_Contents, NULL,
            MUIA_CycleChain, 1,
          End,
          Child, Label("URL"),
          Child, UWin->STR_URL = TextinputObject,
            MUIA_Frame, MUIV_Frame_String,
            MUIA_Textinput_Multiline, FALSE,
            MUIA_Textinput_MaxLen, 450,
            MUIA_Textinput_Contents, NULL,
            MUIA_CycleChain, 1,
          End,
        End,
        Child, HGroup,
          Child, HSpace(0),
          Child, UWin->BT_URLSend = SimpleButton("Send This URL"),
          Child, HSpace(0),
        End,
      End,
/**/  Child, VGroup,
        Child, HGroup,
          Child, UWin->LV_InfoPages = NListviewObject,
            MUIA_CycleChain, TRUE,
            MUIA_NListview_NList, NListObject,
              MUIA_Frame, MUIV_Frame_String,
              MUIA_NList_ConstructHook, MUIV_NList_ConstructHook_String,
              MUIA_NList_DestructHook, MUIV_NList_DestructHook_String,
              MUIA_NList_AdjustWidth, TRUE,
              MUIA_NList_SourceArray, InfoPages,
            End,
          End,
          Child, UWin->GP_InfoPages = GroupObject,
            MUIA_Group_PageMode, TRUE,
            MUIA_Frame, MUIV_Frame_Group,
            Child, VGroup,
              Child, HVSpace,
              Child, HGroup,
                MUIA_Frame, MUIV_Frame_Group,
                MUIA_FrameTitle, "ICQ Number",
                Child, Label("ICQ#"),
                Child, UWin->TX_UIN = TextObject,
                  MUIA_Background, MUII_TextBack,
                  MUIA_Frame, MUIV_Frame_Text,
                  MUIA_Text_Contents, NULL,
                End,
                Child, Label("Current / Last IP"),
                Child, UWin->TX_IP = TextObject,
                  MUIA_Background, MUII_TextBack,
                  MUIA_Frame, MUIV_Frame_Text,
                  MUIA_Text_Contents, NULL,
                End,
              End,
              Child, HGroup,
                MUIA_Frame, MUIV_Frame_Group,
                MUIA_FrameTitle, "Name",
                MUIA_Group_Columns, 4,
                Child, Label("First Name"),
                Child, UWin->STR_First = TextinputObject,
                  MUIA_Frame, MUIV_Frame_String,
                  MUIA_Textinput_Contents, NULL,
                  MUIA_CycleChain, TRUE,
                End,
                Child, Label("Last Name"),
                Child, UWin->STR_Last = TextinputObject,
                  MUIA_Frame, MUIV_Frame_String,
                  MUIA_Textinput_Contents, NULL,
                  MUIA_CycleChain, TRUE,
                End,
                Child, Label("Nickname"),
                Child, UWin->STR_Nick = TextinputObject,
                  MUIA_Frame, MUIV_Frame_String,
                  MUIA_Textinput_Contents, NULL,
                  MUIA_CycleChain, TRUE,
                End,
                Child, Label("Display"),
                Child, HGroup,
                  Child, HSpace(0),
                  Child, CLabel("Coming soon..."),
                  Child, HSpace(0),
                End,
              End,
              Child, HGroup,
                MUIA_Frame, MUIV_Frame_Group,
                MUIA_FrameTitle, "EMail Addresses",
                MUIA_Group_Columns, 2,
                Child, Label("Primary EMail"),
                Child, UWin->STR_EMail = TextinputObject,
                  MUIA_Frame, MUIV_Frame_String,
                  MUIA_Textinput_Contents, NULL,
                  MUIA_Textinput_Editable, FALSE,
                  MUIA_CycleChain, TRUE,
                End,
                Child, HGroup,
                  Child, HSpace(0),
                  Child, UWin->CH_EditEMail = ImageObject,
                    MUIA_Frame, MUIV_Frame_ImageButton,
                    MUIA_InputMode, MUIV_InputMode_Toggle,
                    MUIA_Image_Spec, MUII_CheckMark,
                    MUIA_Image_FreeVert, TRUE,
                    MUIA_Selected, FALSE,
                    MUIA_Background, MUII_ButtonBack,
                    MUIA_ShowSelState, FALSE,
                    MUIA_CycleChain, TRUE,
                  End,
                End,
                Child, HGroup,
                  Child, LLabel("Don't update Primary EMail address"),
                  Child, HSpace(0),
                End,
                Child, Label("Secondary EMail"),
                Child, UWin->TX_EMail2 = TextObject,
                  MUIA_Background, MUII_TextBack,
                  MUIA_Frame, MUIV_Frame_Text,
                  MUIA_Text_Contents, NULL,
                End,
                Child, Label("Old EMail"),
                Child, UWin->TX_EMailOld = TextObject,
                  MUIA_Background, MUII_TextBack,
                  MUIA_Frame, MUIV_Frame_Text,
                  MUIA_Text_Contents, NULL,
                End,
              End,
              Child, HVSpace,
            End,
            Child, VGroup,
              Child, HVSpace,
              Child, HGroup,
                MUIA_Frame, MUIV_Frame_Group,
                MUIA_FrameTitle, "Home Address",
                MUIA_Group_Columns, 3,
                Child, VGroup,
                  Child, CLabel("Street"),
                  Child, Label("Address"),
                End,
                Child, UWin->TI_StreetAd = TextinputObject,
                  MUIA_Frame, MUIV_Frame_String,
                  MUIA_Textinput_Multiline, TRUE,
                  MUIA_Textinput_Contents, NULL,
                  MUIA_Textinput_MaxLen, 512,
                  MUIA_Textinput_Editable, FALSE,
                End,
                Child, VGroup,
                  MUIA_Group_Columns, 2,
                  Child, Label("City"),
                  Child, UWin->TX_City = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                  Child, Label("State"),
                  Child, UWin->TX_State = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                  Child, Label("Zip Code"),
                  Child, UWin->TX_ZipCode = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                End,
                Child, HSpace(0),
                Child, UWin->BT_DisplayMap = SimpleButton("Display Map"),
                Child, HGroup,
                  Child, Label("Country"),
                  Child, UWin->TX_Country = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                End,
              End,
              Child, HGroup,
                Child, VGroup,
                  MUIA_Frame, MUIV_Frame_Group,
                  MUIA_FrameTitle, "Phone Directory Listings",
                  MUIA_Group_Columns, 2,
                  Child, Label("Phone"),
                  Child, UWin->TX_Phone = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                  Child, Label("FAX"),
                  Child, UWin->TX_FAX = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                  Child, Label("Cellular"),
                  Child, UWin->TX_Cellular = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                End,
                Child, VGroup,
                  MUIA_Frame, MUIV_Frame_Group,
                  MUIA_FrameTitle, "Local Time",
                  MUIA_Group_Columns, 2,
                  Child, Label("Time Zone"),
                  Child, UWin->NU_TimeZone = SliderObject,
                    MUIA_Numeric_Max, 12,
                    MUIA_Numeric_Min, -12,
                  End,
                  Child, Label("Local Time"),
                  Child, UWin->TX_LocalTime = TextObject,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Text_Contents, NULL,
                    MUIA_Text_PreParse, "\033c",
                  End,
                  Child, Label("User Time"),
                  Child, UWin->TX_UserTime = TextObject,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Text_Contents, NULL,
                    MUIA_Text_PreParse, "\033c",
                  End,
                End,
              End,
              Child, HVSpace,
            End,
            Child, VGroup,
              Child, HVSpace,
              Child, VGroup,
                MUIA_Frame, MUIV_Frame_Group,
                MUIA_FrameTitle, "Additional Details",
                Child, HGroup,
                  Child, Label("Home Page"),
                  Child, UWin->BT_HomePage = TextObject,
                    MUIA_Frame, MUIV_Frame_Button,
                    MUIA_Font, MUIV_Font_Button,
                    MUIA_Text_Contents, NULL,
                    MUIA_Text_PreParse, "\33c",
                    MUIA_InputMode, MUIV_InputMode_RelVerify,
                    MUIA_Background, MUII_ButtonBack,
                    MUIA_UserData, id,
                    MUIA_CycleChain, TRUE,
                  End,
                End,
                Child, HGroup,
                  Child, Label("Gender"),
                  Child, UWin->TX_Sex = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                  Child, Label("Age"),
                  Child, UWin->TX_Age = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                  Child, UWin->BT_URLCategory = SimpleButton("Homepage Category"),
                End,
              End,
              Child, VGroup,
                MUIA_Frame, MUIV_Frame_Group,
                MUIA_FrameTitle, "Birth Date & Horoscope",
                Child, HGroup,
                  Child, Label("Month"),
                  Child, UWin->TX_BDMonth = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                  Child, Label("Day"),
                  Child, UWin->TX_BDDay = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                  Child, Label("Year"),
                  Child, UWin->TX_BDYear = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                  Child, Label("Zodiac"),
                  Child, UWin->GP_DTGroup = GroupObject,
                    Child, UWin->DT_Zodiac = DatatypeObject,
//                    MUIA_Dtpic_Name, zodiac,
                    End,
                  End,
                End,
                Child, HGroup,
                  Child, UWin->CH_BDNotify = ImageObject,
                    MUIA_Frame, MUIV_Frame_ImageButton,
                    MUIA_InputMode, MUIV_InputMode_Toggle,
                    MUIA_Image_Spec, MUII_CheckMark,
                    MUIA_Image_FreeVert, TRUE,
                    MUIA_Selected, TRUE,
                    MUIA_Background, MUII_ButtonBack,
                    MUIA_ShowSelState, FALSE,
                    MUIA_CycleChain, TRUE,
                  End,
                  Child, LLabel("Notify me xx days before the birthday"),
                  Child, UWin->BT_ViewHoroscope = SimpleButton("View Horoscope"),
                End,
              End,
              Child, VGroup,
                MUIA_Frame, MUIV_Frame_Group,
                MUIA_FrameTitle, "Spoken Languages",
                Child, HGroup,
                  Child, UWin->TX_Lang1 = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                  Child, UWin->TX_Lang2 = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                  Child, UWin->TX_Lang3 = TextObject,
                    MUIA_Frame, MUIV_Frame_Text,
                    MUIA_Background, MUII_TextBack,
                    MUIA_Text_Contents, NULL,
                  End,
                End,
              End,
              Child, HVSpace,
            End,
            Child, VGroup,
              Child, VGroup,
                MUIA_Frame, MUIV_Frame_Group,
                MUIA_FrameTitle, "Additional Details About The User",
                Child, HGroup,
                  MUIA_Group_Spacing, 0,
                  Child, UWin->TE_About = TextEditorObject,
                    MUIA_Frame, MUIV_Frame_String,
                    MUIA_TextEditor_ReadOnly, TRUE,
                    MUIA_TextEditor_Slider, UWin->SC_AboutScroll,
                  End,
                  Child, UWin->SC_AboutScroll,
                End,
              End,
              Child, VGroup,
                MUIA_Frame, MUIV_Frame_Group,
                MUIA_FrameTitle, "Enter Additional Info/Notes About The User",
                Child, HGroup,
                  MUIA_Group_Spacing, 0,
                  Child, UWin->TE_Comment = TextEditorObject,
                    MUIA_Frame, MUIV_Frame_String,
                    MUIA_TextEditor_Slider, UWin->SC_CommentScroll,
                    MUIA_CycleChain, TRUE,
                  End,
                  Child, UWin->SC_CommentScroll,
                End,
              End,
            End,
            Child, VGroup,
              Child, HVSpace,
              Child, VGroup,
                MUIA_Frame, MUIV_Frame_Group,
                MUIA_FrameTitle, "Options",
                MUIA_Group_Columns, 3,
                Child, UWin->CH_SeeInvis = ImageObject,
                  MUIA_Frame, MUIV_Frame_ImageButton,
                  MUIA_InputMode, MUIV_InputMode_Toggle,
                  MUIA_Image_Spec, MUII_CheckMark,
                  MUIA_Image_FreeVert, TRUE,
                  MUIA_Selected, user->SeeInvis,
                  MUIA_Background, MUII_ButtonBack,
                  MUIA_ShowSelState, FALSE,
                  MUIA_CycleChain, TRUE,
                  MUIA_ShortHelp, "Tick this box to allow this user to\nsee you while you are 'Invisible'",
                  MUIA_UserData, id,
                End,
                Child, LLabel("Visible To User"),
                Child, HSpace(0),
                Child, UWin->CH_BeInvis = ImageObject,
                  MUIA_Frame, MUIV_Frame_ImageButton,
                  MUIA_InputMode, MUIV_InputMode_Toggle,
                  MUIA_Image_Spec, MUII_CheckMark,
                  MUIA_Image_FreeVert, TRUE,
                  MUIA_Selected, user->BeInvis,
                  MUIA_Background, MUII_ButtonBack,
                  MUIA_ShowSelState, FALSE,
                  MUIA_CycleChain, TRUE,
                  MUIA_ShortHelp, "Tick this box and this user\nwill never see you Online",
                  MUIA_UserData, id,
                End,
                Child, LLabel("Invisible To User"),
                Child, HSpace(0),
              End,
              Child, VGroup,
                MUIA_Frame, MUIV_Frame_Group,
                MUIA_FrameTitle, "Last Seen",
                MUIA_Group_Columns, 2,
                Child, Label("Connecté"),
                Child, UWin->TX_LastOnline = TextObject,
                  MUIA_Frame, MUIV_Frame_Text,
                  MUIA_Background, MUII_TextBack,
                  MUIA_Text_Contents, NULL,
                End,
                Child, Label("Message To"),
                Child, UWin->TX_MessageTo = TextObject,
                  MUIA_Frame, MUIV_Frame_Text,
                  MUIA_Background, MUII_TextBack,
                  MUIA_Text_Contents, NULL,
                End,
                Child, Label("Message From"),
                Child, UWin->TX_MessageFm = TextObject,
                  MUIA_Frame, MUIV_Frame_Text,
                  MUIA_Background, MUII_TextBack,
                  MUIA_Text_Contents, NULL,
                End,
              End,
              Child, HVSpace,
            End,
          End,
        End,
        Child, HGroup,
          Child, UWin->BT_Load = SimpleButton("Load"),
          Child, UWin->BT_Save = SimpleButton("Save"),
          Child, UWin->BT_Query = SimpleButton("Refresh"),
        End,
      End,
/**/  Child, VGroup,
        Child, UWin->LV_History = NListviewObject,
          MUIA_NListview_NList, NListObject,
            MUIA_Frame, MUIV_Frame_String,
            MUIA_NList_MultiSelect, MUIV_NList_MultiSelect_Default,
            MUIA_NList_ConstructHook, MUIV_NList_ConstructHook_String,
            MUIA_NList_DestructHook, MUIV_NList_DestructHook_String,
          End,
        End,
        Child, HGroup,
          Child, UWin->BT_LoadHist = KeyButton("Load",'l'),
          Child, UWin->BT_RemoveLine = KeyButton("Remove Line",'r'),
          Child, UWin->BT_ClearHist = KeyButton("Clear",'c'),
          Child, UWin->BT_SaveHist = KeyButton("Save",'s'),
          Child, UWin->BT_DeleteHist = KeyButton("Delete",'d'),
        End,
      End,
    End,
  End,
End;

if (!UWin->WI_UserWindow) {
  HandleError(DBG_OTH_FATL,"Could not create User Window.");
  if (UWin->SC_AboutScroll) MUI_DisposeObject(UWin->SC_AboutScroll);
  if (UWin->SC_CommentScroll) MUI_DisposeObject(UWin->SC_CommentScroll);
  FreeVec(UWin);
  UWin = NULL;
  return(FALSE);
}

user->UWin = UWin;

DoMethod(app->App,OM_ADDMEMBER,UWin->WI_UserWindow);

set(UWin->BT_IgnoreMe,MUIA_UserData,id);
set(UWin->BT_ChatReq,MUIA_UserData,id);
set(UWin->BT_FileSend,MUIA_UserData,id);
set(UWin->BT_Forward,MUIA_UserData,id);
set(UWin->BT_Save,MUIA_UserData,id);
set(UWin->BT_Query,MUIA_UserData,id);
set(UWin->BT_URLSend,MUIA_UserData,id);
set(UWin->BT_Auth,MUIA_UserData,id);
set(UWin->BT_HomePage,MUIA_UserData,id);
set(UWin->BT_LoadHist,MUIA_UserData,id);
set(UWin->BT_SaveHist,MUIA_UserData,id);
set(UWin->BT_DeleteHist,MUIA_UserData,id);
set(UWin->LV_Msgs,MUIA_UserData,id);
set(UWin->BT_Contacts,MUIA_UserData,id);
set(UWin->BT_WhitePage,MUIA_UserData,id);

set(UWin->BB_WaitTCP,MUIA_ShowMe,FALSE);
set(UWin->BT_SendIt,MUIA_ShowMe,multiline);

set(UWin->BT_URLSend,MUIA_CycleChain,TRUE);
set(UWin->BT_IgnoreMe,MUIA_CycleChain,TRUE);
set(UWin->BT_Clear,MUIA_CycleChain,TRUE);
set(UWin->BT_Auth,MUIA_CycleChain,TRUE);
set(UWin->BT_ChatReq,MUIA_CycleChain,TRUE);
set(UWin->BT_FileSend,MUIA_CycleChain,TRUE);
set(UWin->BT_Forward,MUIA_CycleChain,TRUE);
set(UWin->BT_Contacts,MUIA_CycleChain,TRUE);
set(UWin->BT_WhitePage,MUIA_CycleChain,TRUE);
set(UWin->BT_Load,MUIA_CycleChain,TRUE);
set(UWin->BT_Save,MUIA_CycleChain,TRUE);
set(UWin->BT_Query,MUIA_CycleChain,TRUE);
set(UWin->BT_URLCategory,MUIA_CycleChain,TRUE);
set(UWin->BT_DisplayMap,MUIA_CycleChain,TRUE);
set(UWin->CH_EditEMail,MUIA_CycleChain,TRUE);

if (!usetime) set(UWin->LV_Msgs,MUIA_NList_Format,"COL=0 BAR,COL=2");

UpdateUserWin(user);

DoMethod(UWin->WI_UserWindow, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, UWin->WI_UserWindow, 3,
         MUIM_Set, MUIA_Window_Open, FALSE);

DoMethod(UWin->BT_Clear, MUIM_Notify, MUIA_Pressed, FALSE, UWin->LV_Msgs, 1,
         MUIM_NList_Clear);

DoMethod(UWin->BT_Clear, MUIM_Notify, MUIA_Pressed, FALSE, UWin->POP_Choices, 1,
         MUIM_Popstring_Close);

DoMethod(UWin->TI_QuickMsg, MUIM_Notify, MUIA_Textinput_Acknowledge, MUIV_EveryTime, UWin->TI_QuickMsg, 2,
         MUIM_CallHook, &SendMsg2ICQaHook);

DoMethod(UWin->BT_SendIt, MUIM_Notify, MUIA_Pressed, FALSE, UWin->TI_QuickMsg, 2,
         MUIM_CallHook, &SendMsg2ICQaHook);

DoMethod(UWin->BT_IgnoreMe, MUIM_Notify, MUIA_Pressed, FALSE, UWin->BT_IgnoreMe, 2,
         MUIM_CallHook, &Add2IgnoreHook);

DoMethod(UWin->BT_IgnoreMe, MUIM_Notify, MUIA_Pressed, FALSE, UWin->POP_Choices, 1,
         MUIM_Popstring_Close);

DoMethod(UWin->BT_Auth, MUIM_Notify, MUIA_Pressed, FALSE, UWin->BT_Auth, 2,
         MUIM_CallHook, &SendMsg2ICQaHook);

DoMethod(UWin->BT_Auth, MUIM_Notify, MUIA_Pressed, FALSE, UWin->POP_Choices, 1,
         MUIM_Popstring_Close);

DoMethod(UWin->BT_ChatReq, MUIM_Notify, MUIA_Pressed, FALSE, UWin->BT_ChatReq, 2,
         MUIM_CallHook, &OpenChatReqWinHook);

DoMethod(UWin->BT_ChatReq, MUIM_Notify, MUIA_Pressed, FALSE, UWin->POP_Choices, 1,
         MUIM_Popstring_Close);

DoMethod(UWin->BT_FileSend, MUIM_Notify, MUIA_Pressed, FALSE, UWin->BT_FileSend, 2,
         MUIM_CallHook, &OpenFileDirectWinHook);

DoMethod(UWin->BT_FileSend, MUIM_Notify, MUIA_Pressed, FALSE, UWin->POP_Choices, 1,
         MUIM_Popstring_Close);

DoMethod(UWin->BT_Forward, MUIM_Notify, MUIA_Pressed, FALSE, UWin->BT_Forward, 2,
         MUIM_CallHook, &ForwardMsgHook);

DoMethod(UWin->BT_Forward, MUIM_Notify, MUIA_Pressed, FALSE, UWin->POP_Choices, 1,
         MUIM_Popstring_Close);

DoMethod(UWin->BT_Contacts, MUIM_Notify, MUIA_Pressed, FALSE, UWin->BT_Contacts, 2,
         MUIM_CallHook, &ShareContactsHook);

DoMethod(UWin->BT_Contacts, MUIM_Notify, MUIA_Pressed, FALSE, UWin->POP_Choices, 1,
         MUIM_Popstring_Close);

DoMethod(UWin->BT_WhitePage, MUIM_Notify, MUIA_Pressed, FALSE, UWin->BT_WhitePage, 2,
         MUIM_CallHook, &GoURLHook);

DoMethod(UWin->BT_WhitePage, MUIM_Notify, MUIA_Pressed, FALSE, UWin->POP_Choices, 1,
         MUIM_Popstring_Close);

DoMethod(UWin->BT_URLSend, MUIM_Notify, MUIA_Pressed, FALSE, UWin->BT_URLSend, 2,
         MUIM_CallHook, &SendMsg2ICQaHook);

DoMethod(UWin->BT_Query, MUIM_Notify, MUIA_Pressed, FALSE, UWin->BT_Query, 2,
         MUIM_CallHook, &GetUINInfoHook);

DoMethod(UWin->CH_SeeInvis, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, UWin->CH_SeeInvis, 2,
         MUIM_CallHook, &SetUserVisPrefsHook);

DoMethod(UWin->CH_BeInvis, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, UWin->CH_BeInvis, 2,
         MUIM_CallHook, &SetUserVisPrefsHook);

DoMethod(UWin->BT_Save, MUIM_Notify, MUIA_Pressed, FALSE, UWin->BT_Save, 2,
         MUIM_CallHook, &SaveContactJumpHook);

DoMethod(UWin->BT_LoadHist, MUIM_Notify, MUIA_Pressed, FALSE, UWin->BT_LoadHist, 2,
         MUIM_CallHook, &LoadHistoryHook);

DoMethod(UWin->BT_RemoveLine, MUIM_Notify, MUIA_Pressed, FALSE, UWin->LV_History, 2,
         MUIM_NList_Remove, MUIV_NList_Remove_Selected);

DoMethod(UWin->BT_ClearHist, MUIM_Notify, MUIA_Pressed, FALSE, UWin->LV_History, 1,
         MUIM_NList_Clear);

DoMethod(UWin->BT_SaveHist, MUIM_Notify, MUIA_Pressed, FALSE, UWin->BT_SaveHist, 2,
         MUIM_CallHook, &SaveHistoryHook);

DoMethod(UWin->BT_DeleteHist, MUIM_Notify, MUIA_Pressed, FALSE, UWin->BT_DeleteHist, 2,
         MUIM_CallHook, &DeleteHistoryHook);

DoMethod(UWin->LV_Msgs, MUIM_Notify, MUIA_NList_DoubleClick, MUIV_EveryTime, UWin->LV_Msgs, 2,
         MUIM_CallHook, &GoURLHook);

DoMethod(UWin->BT_HomePage, MUIM_Notify, MUIA_Pressed, FALSE, UWin->BT_HomePage, 2,
         MUIM_CallHook, &GoURLHook);

DoMethod(UWin->LV_InfoPages, MUIM_Notify, MUIA_NList_EntryClick, MUIV_EveryTime, UWin->GP_InfoPages, 3,
         MUIM_Set, MUIA_Group_ActivePage, MUIV_TriggerValue);

DoMethod(UWin->CH_EditEMail, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, UWin->STR_EMail, 3,
         MUIM_Set, MUIA_Textinput_Editable, MUIV_TriggerValue);

DoMethod(UWin->CH_EditEMail, MUIM_Notify, MUIA_Selected, MUIV_EveryTime, UWin->CH_EditEMail, 2,
         MUIM_CallHook, &SetUserVisPrefsHook);

return(TRUE);

}


struct Contact *GetContact(ULONG uin)

{

int i;

ULONG total;

struct Contact *user;

get(app->LV_OfflineList,MUIA_NList_Entries,&total);

for(i = 0; i < total; i++) {
  DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,i,&user);
  if (user) if (user->UIN == uin) {
    user->ListID = i;
    return(user);
  }
}

return(NULL);

}


struct Sockets *GetSocketFmSocket(UWORD sock)

{

int i;

ULONG total;

struct Sockets *socks;

if (sock < 0) return(NULL);

get(app->LV_SockList,MUIA_NList_Entries,&total);

if (!total) return(NULL);

for(i = 0; i < total; i++) {
  DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  if (socks) if (socks->Socket == sock) return(socks);
}

return(NULL);

}


struct Sockets *GetSocketFmPort(UWORD port)

{

int i;

ULONG total;

struct Sockets *socks;

HandleError(DBG_TCP_DBUG,"GetSocketFmPort(%d)",port);

if (port < 0) return(NULL);

get(app->LV_SockList,MUIA_NList_Entries,&total);

if (!total) return(NULL);

for(i = 0; i < total; i++) {
  DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  if (socks) {
    if (socks->Port == port) {
      HandleError(DBG_TCP_DBUG,"Socket %d has port %d",socks->Socket,socks->Port);
      return(socks);
    }
  }
}

return(NULL);

}


struct Sockets *GetSocketFmContact(struct Contact *user, UBYTE type)

{

int i;

ULONG total;

struct Sockets *socks;

if (!user) return(NULL);

get(app->LV_SockList,MUIA_NList_Entries,&total);

if (!total) return(NULL);

for(i = 0; i < total; i++) {
  DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  if (socks) if (socks->UIN == user->UIN && socks->Type == type && socks->Dir != TCP_DIR_LISTEN) return(socks);
}

return(NULL);

}


void UpdateUserWin(struct Contact *user)

{

LONG zone;

struct ColorText *ct;

if (!user) return;
if (!user->UWin) return;
if (!user->UWin->WI_UserWindow) return;

set(user->UWin->STR_Nick,MUIA_String_Contents,user->Nick);

sprintf(user->UWin->UIN,"%ld",user->UIN);
set(user->UWin->TX_UIN,MUIA_Text_Contents,user->UWin->UIN);

ct = GetStatus(user->Status);
strcpy(user->UWin->Status,ct->Status);

if (user->Status & STATUSF_HIDEIP) strcpy(user->UWin->IP,"Hidden");
else sprintf(user->UWin->IP,"%s:%ld",Inet_NtoA(user->IP),user->Port);
set(user->UWin->TX_IP,MUIA_Text_Contents,user->UWin->IP);

set(user->UWin->STR_First,MUIA_String_Contents,user->First);
set(user->UWin->STR_Last,MUIA_String_Contents,user->Last);
set(user->UWin->STR_EMail,MUIA_String_Contents,user->EMail);
set(user->UWin->TX_EMail2,MUIA_String_Contents,user->EMail_Secondary);
set(user->UWin->TX_EMailOld,MUIA_String_Contents,user->EMail_Old);

set(user->UWin->TI_StreetAd,MUIA_Textinput_Contents,user->Street);

set(user->UWin->TX_City,MUIA_Text_Contents,user->City);

if (user->Country == 0xffff) strcpy(user->UWin->Country,"Unspecified");
else sprintf(user->UWin->Country,"%s",FindCountryName(user->Country));
set(user->UWin->TX_Country,MUIA_Text_Contents,user->UWin->Country);

zone = user->TimeZone;

set(user->UWin->NU_TimeZone,MUIA_Numeric_Value,zone);

set(user->UWin->TX_State,MUIA_Text_Contents,user->State);
set(user->UWin->TX_ZipCode,MUIA_Text_Contents,user->ZipCode);

if (user->Age == 0xffff) strcpy(user->UWin->Age,"Unspecified");
else sprintf(user->UWin->Age,"%d",user->Age);
set(user->UWin->TX_Age,MUIA_Text_Contents,user->UWin->Age);

switch(user->Sex) {
  case 0x00:
    strcpy(user->UWin->Sex,"Unspecified");
    break;
  case 0x01:
    strcpy(user->UWin->Sex,"Female");
    break;
  case 0x02:
    strcpy(user->UWin->Sex,"Male");
    break;
};
set(user->UWin->TX_Sex,MUIA_Text_Contents,user->UWin->Sex);

if (user->BDay_Day) sprintf(user->UWin->Day,"%d",user->BDay_Day);
else strcpy(user->UWin->Day,"N/A");
if (user->BDay_Year) sprintf(user->UWin->Year,"%d",user->BDay_Year);
else strcpy(user->UWin->Year,"N/A");

set(user->UWin->TX_BDMonth,MUIA_Text_Contents,Months[user->BDay_Month]);
set(user->UWin->TX_BDDay,MUIA_Text_Contents,user->UWin->Day);
set(user->UWin->TX_BDYear,MUIA_Text_Contents,user->UWin->Year);

set(user->UWin->TX_Lang1,MUIA_Text_Contents,Languages[user->Language1]);
set(user->UWin->TX_Lang2,MUIA_Text_Contents,Languages[user->Language2]);
set(user->UWin->TX_Lang3,MUIA_Text_Contents,Languages[user->Language3]);

set(user->UWin->TX_Phone,MUIA_Text_Contents,user->Phone);
set(user->UWin->TX_FAX,MUIA_Text_Contents,user->FAX);
set(user->UWin->TX_Cellular,MUIA_Text_Contents,user->Cellular);
set(user->UWin->BT_HomePage,MUIA_Text_Contents,user->HomePage);

set(user->UWin->TE_About,MUIA_TextEditor_Contents,user->About);

set(user->UWin->TE_Comment,MUIA_TextEditor_Contents,user->Comment);

sprintf(user->UWin->Title,"%ld %s (%s)",user->UIN,user->Nick,user->UWin->Status);
set(user->UWin->WI_UserWindow,MUIA_Window_Title,user->UWin->Title);

set(user->UWin->CH_SeeInvis,MUIA_Selected,user->SeeInvis);
set(user->UWin->CH_BeInvis,MUIA_Selected,user->BeInvis);

sprintf(user->UWin->LastOnline,"%s",ctime(&user->LastOnline));
sprintf(user->UWin->MessageTo,"%s",ctime(&user->LastMessageTo));
sprintf(user->UWin->MessageFm,"%s",ctime(&user->LastMessageFm));

LASTCHAR(user->UWin->LastOnline) = '\0';
LASTCHAR(user->UWin->MessageTo) = '\0';
LASTCHAR(user->UWin->MessageFm) = '\0';

set(user->UWin->TX_LastOnline,MUIA_Text_Contents,user->UWin->LastOnline);
set(user->UWin->TX_MessageTo,MUIA_Text_Contents,user->UWin->MessageTo);
set(user->UWin->TX_MessageFm,MUIA_Text_Contents,user->UWin->MessageFm);

if (user->BDay_Day > 0 && user->BDay_Year > 0) ChangeZodiacPic(user,FALSE);

return;

}


struct ColorText *GetStatus(ULONG status)

{

ULONG bday, stat;

static struct ColorText cd;

bday = status & STATUSF_BIRTHDAY;
stat = status & STATUS_OFFLINE;

switch(stat) {
  case STATUS_ONLINE:
  case STAT_ONLINE_99:
    sprintf(cd.Status,"Online");
    cd.Pen = Pens.StatusColors[ONLINE];
    break;
  case STATUS_AWAY:
  case STAT_AWAY_99:
    sprintf(cd.Status,"Away");
    cd.Pen = Pens.StatusColors[AWAY];
    break;
  case STAT_DND:
  case STAT_DND_2:
  case STAT_DND_3:
    sprintf(cd.Status,"DND");
    cd.Pen = Pens.StatusColors[DONOTDISTURB];
    break;
  case STAT_INVISIBLE:
    sprintf(cd.Status,"Invisible");
    cd.Pen = Pens.StatusColors[INVISIBLE];
    break;
  case STATUS_OFFLINE:
    sprintf(cd.Status,"Offline");
    cd.Pen = Pens.StatusColors[OFFLINE];
    break;
  case STATUS_NA:
  case STAT_NA_99:
    sprintf(cd.Status,"Not Available");
    cd.Pen = Pens.StatusColors[NOTAVAILABLE];
    break;
  case STAT_FREE_CHAT:
  case STAT_FREE_CHAT_99:
    sprintf(cd.Status,"Free For Chat");
    cd.Pen = Pens.StatusColors[FREEFORCHAT];
    break;
  case STAT_OCCUPIED:
  case STAT_OCCUPIED_99:
    sprintf(cd.Status,"Occupied");
    cd.Pen = Pens.StatusColors[OCCUPIED];
    break;
  case STATUS_NEWUIN:
    sprintf(cd.Status,"New User");
    cd.Pen = Pens.StatusColors[NEWUSER];
    break;
  default:
    sprintf(cd.Status,"%08x",status);
    cd.Pen = 2;
}

return(&cd);

}


void SaveContact(ULONG uin)

{

char buf[512];

struct AsyncFile *save_fh;
struct Contact *user;

if (!(user = GetContact(uin))) return;

if (user->Status == STATUS_NEWUIN) return;

sprintf(userstat_fl,"%s%ld",userdir_fl,uin);

if (!(save_fh = OpenAsync(userstat_fl,MODE_WRITE,AsyncBuf))) {
  HandleError(DBG_OTH_INFO,"Could not open '%s' for saving.",userstat_fl);
  return;
}

sprintf(buf,"NICK=%s\n",(user->Nick?user->Nick:LINE));
WriteLineAsync(save_fh,buf);

sprintf(buf,"FIRST=%s\n",(user->First?user->First:LINE));
WriteLineAsync(save_fh,buf);

sprintf(buf,"LAST=%s\n",(user->Last?user->Last:LINE));
WriteLineAsync(save_fh,buf);

sprintf(buf,"EMAIL=%s\n",(user->EMail?user->EMail:LINE));
WriteLineAsync(save_fh,buf);

sprintf(buf,"CITY=%s\n",(user->City?user->City:LINE));
WriteLineAsync(save_fh,buf);

sprintf(buf,"STATE=%s\n",(user->State?user->State:LINE));
WriteLineAsync(save_fh,buf);

sprintf(buf,"PHONE=%s\n",(user->Phone?user->Phone:LINE));
WriteLineAsync(save_fh,buf);

sprintf(buf,"HOMEPAGE=%s\n",(user->HomePage?user->HomePage:LINE));
WriteLineAsync(save_fh,buf);

sprintf(buf,"COUNTRY=%d\n",user->Country);
WriteLineAsync(save_fh,buf);

sprintf(buf,"AGE=%d\n",user->Age);
WriteLineAsync(save_fh,buf);

sprintf(buf,"SEX=%d\n",user->Sex);
WriteLineAsync(save_fh,buf);

sprintf(buf,"AUTHORIZE=%d\n",user->Authorize);
WriteLineAsync(save_fh,buf);

sprintf(buf,"SEEINVIS=%d\n",user->SeeInvis);
WriteLineAsync(save_fh,buf);

WriteLineAsync(save_fh,"ABOUT=\n");

sprintf(buf,"%s\n;\n",(user->About?user->About:LINE));
WriteLineAsync(save_fh,buf);

WriteLineAsync(save_fh,"COMMENT=\n");

sprintf(buf,"%s\n;\n",(user->Comment?user->Comment:LINE));
WriteLineAsync(save_fh,buf);

sprintf(buf,"NEWMSGS=%d\n",user->NewMsg);
WriteLineAsync(save_fh,buf);

sprintf(buf,"TIMEZONE=%d\n",user->TimeZone);
WriteLineAsync(save_fh,buf);

sprintf(buf,"BEINVIS=%d\n",user->BeInvis);
WriteLineAsync(save_fh,buf);

sprintf(buf,"LASTONLINE=%ld\n",user->LastOnline);
WriteLineAsync(save_fh,buf);

sprintf(buf,"LASTMESSAGEFM=%ld\n",user->LastMessageFm);
WriteLineAsync(save_fh,buf);

sprintf(buf,"LASTMESSAGETO=%ld\n",user->LastMessageTo);
WriteLineAsync(save_fh,buf);

CloseAsync(save_fh);

user->Changed = FALSE;

SetComment(userstat_fl,user->Nick);

return;

}


void __asm SaveContactJump(REG(a2) APTR obj)

{

char *tmp, about[512];

int i;

ULONG id = 0, total = 0;

struct Contact User, *user;

PrepNewContact(&User);

get(obj,MUIA_UserData,&id);

user = GetContact(id);

get(user->UWin->STR_Nick,MUIA_Textinput_Contents,&tmp);
User.Nick = tmp;

get(user->UWin->STR_First,MUIA_Textinput_Contents,&tmp);
User.First = tmp;

get(user->UWin->STR_Last,MUIA_Textinput_Contents,&tmp);
User.Last = tmp;

get(user->UWin->STR_EMail,MUIA_Textinput_Contents,&tmp);
User.EMail = tmp;

get(user->UWin->TX_City,MUIA_Text_Contents,&tmp);
User.City = tmp;

get(user->UWin->TX_State,MUIA_Text_Contents,&tmp);
User.State = tmp;

get(user->UWin->TX_Phone,MUIA_Text_Contents,&tmp);
User.Phone = tmp;

get(user->UWin->BT_HomePage,MUIA_Text_Contents,&tmp);
User.HomePage = tmp;

strcpy(about,user->About);

User.UIN = user->UIN;
User.About = about;
User.Country = user->Country;
User.TimeZone = user->TimeZone;
User.Age = user->Age;
User.Sex = user->Sex;
User.Authorize = user->Authorize;
User.IP = user->IP;
User.Port = user->Port;
User.RealIP = user->RealIP;
User.Status = user->Status;
User.SeeInvis = user->SeeInvis;
User.BeInvis = user->BeInvis;
User.LastOnline = user->LastOnline;
User.LastMessageFm = user->LastMessageFm;
User.LastMessageTo = user->LastMessageTo;

User.Comment = (char *)DoMethod(user->UWin->TE_Comment,MUIM_TextEditor_ExportText);

User.UWin = user->UWin;

user->UWin->DoNotDelete = TRUE;

get(app->LV_OfflineList,MUIA_NList_Entries,&total);

for(i = 0; i < total; i++) {
  DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,i,&user);
  if (user) {
    if (user->UIN == id) {
      DoMethod(app->LV_OfflineList,MUIM_NList_Remove,i);
      break;
    }
  }
}

AddUser2CList(&User);

if (User.Comment) FreeVec(User.Comment);

SaveContact(id);

return;

}


BOOL LoadContact(ULONG uin)

{

char *data, about[512], cmnt[512], line[512];

LONG temp, lamp;

struct AsyncFile *load_fh;
struct Contact User, *user;

PrepNewContact(&User);

sprintf(userstat_fl,"%s%ld",userdir_fl,uin);

if (!(load_fh = OpenAsync(userstat_fl,MODE_READ,AsyncBuf))) {
  HandleError(DBG_OTH_INFO,"Could not open '%s' for loading.",userstat_fl);
  return(FALSE);
}

about[0] = cmnt[0] = '\0';

User.UIN = uin;

while(ReadLineAsync(load_fh,line,sizeof(line))) {
  if (line[0] == ';' || !(data = strchr(line,'='))) continue;
  *data++ = '\0';
  LASTCHAR(data) = '\0';
  if (!stricmp(line,"NICK")) RefreshUInfo(&User.Nick,data);
  if (!stricmp(line,"FIRST")) RefreshUInfo(&User.First,data);
  if (!stricmp(line,"LAST")) RefreshUInfo(&User.Last,data);
  if (!stricmp(line,"EMAIL")) RefreshUInfo(&User.EMail,data);
  if (!stricmp(line,"EMAIL2")) RefreshUInfo(&User.EMail_Secondary,data);
  if (!stricmp(line,"EMAILOLD")) RefreshUInfo(&User.EMail_Old,data);
  if (!stricmp(line,"CITY")) RefreshUInfo(&User.City,data);
  if (!stricmp(line,"STATE")) RefreshUInfo(&User.State,data);
  if (!stricmp(line,"PHONE")) RefreshUInfo(&User.Phone,data);
  if (!stricmp(line,"HOMEPAGE")) RefreshUInfo(&User.HomePage,data);
  if (!stricmp(line,"COUNTRY")) {
    StrToLong(data,&temp);
    User.Country = temp;
    continue;
  }
  if (!stricmp(line,"AGE")) {
    StrToLong(data,&temp);
    User.Age = temp;
    continue;
  }
  if (!stricmp(line,"SEX")) {
    StrToLong(data,&temp);
    User.Sex = temp;
    continue;
  }
  if (!stricmp(line,"AUTHORIZE")) {
    StrToLong(data,&temp);
    User.Authorize = temp;
    continue;
  }
  if (!stricmp(line,"SEEINVIS")) {
    StrToLong(data,&temp);
    User.SeeInvis = temp;
    continue;
  }
  if (!stricmp(line,"ABOUT")) {
    ReadLineAsync(load_fh,line,sizeof(line));
    while(line[0] != ';') {
      strcat(about,line);
      ReadLineAsync(load_fh,line,sizeof(line));
      if (!strnicmp(line,"COMMENT=",8)) {
        data = strchr(line,'=');
        *data++ = '\0';
        OldPrefsFmt = TRUE;
        break;
      }
    }
    LASTCHAR(about) = '\0';
    RefreshUInfo(&User.About,about);
  }
  if (!stricmp(line,"COMMENT")) {
    ReadLineAsync(load_fh,line,sizeof(line));
    while(line[0] != ';') {
      strcat(cmnt,line);
      ReadLineAsync(load_fh,line,sizeof(line));
      if (!strnicmp(line,"NEWMSGS=",8)) {
        data = strchr(line,'=');
        *data++ = '\0';
        break;
      }
    }
    LASTCHAR(cmnt) = '\0';
    RefreshUInfo(&User.Comment,cmnt);
  }
  if (!stricmp(line,"NEWMSGS")) {
    StrToLong(data,&temp);
    User.NewMsg = temp;
    continue;
  }
  if (!stricmp(line,"TIMEZONE")) {
    StrToLong(data,&temp);
    User.TimeZone = temp;
    continue;
  }
  if (!stricmp(line,"BEINVIS")) {
    StrToLong(data,&temp);
    User.BeInvis = temp;
    continue;
  }
  if (!stricmp(line,"LASTONLINE")) {
    StrToLong(data,&temp);
    User.LastOnline = temp;
    continue;
  }
  if (!stricmp(line,"LASTMESSAGEFM")) {
    StrToLong(data,&temp);
    User.LastMessageFm = temp;
    continue;
  }
  if (!stricmp(line,"LASTMESSAGETO")) {
    StrToLong(data,&temp);
    User.LastMessageTo = temp;
    continue;
  }
}

CloseAsync(load_fh);

AddUser2CList(&User);

FreeUser(&User);

user = GetContact(User.UIN);

if (user->NewMsg) {
  switch(user->NewMsg) {
    case 1:
      if (WhichLamp == 0) lamp = MUIV_Lamp_Color_Ok;
      else lamp = MUIV_TWFmultiLED_Colour_On;
      break;
    case 2:
      if (WhichLamp == 0) lamp = MUIV_Lamp_Color_Warning;
      else lamp = MUIV_TWFmultiLED_Colour_Ok;
      break;
    case 3:
      if (WhichLamp == 0) lamp = MUIV_Lamp_Color_Error;
      else lamp = MUIV_TWFmultiLED_Colour_Load;
      break;
    default:
      if (WhichLamp == 0) lamp = MUIV_Lamp_Color_FatalError;
      else lamp = MUIV_TWFmultiLED_Colour_Error;
  }
  if (WhichLamp == 0) set(user->LampObj,MUIA_Lamp_Color,lamp);
  else set(user->LampObj,MUIA_TWFmultiLED_Colour,lamp);
  DoMethod(app->LV_OfflineList,MUIM_NList_Sort);
}

return(TRUE);

}


void __asm LoadContactJump(REG(a2) APTR obj)

{

ULONG id = 0;

get(obj,MUIA_UserData,&id);

LoadContact(id);

UpdateUserWin(GetContact(id));

return;

}


void SaveAllContacts(void)

{

int i;

ULONG total = 0;

struct Contact *user;

get(app->LV_OfflineList,MUIA_NList_Entries,&total);

if (!total) return;

if (OldPrefsFmt) printf("Saving all contacts in new prefs format. (One time message.)\n");

for(i = 0; i < total; i++) {
  DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,i,&user);
  if (user) {
    if (user->Changed || user->NewMsg || OldPrefsFmt) SaveContact(user->UIN);
  }
}

return;

}


void __asm LoadHistory(REG(a2) APTR obj)

{

char uinlog[MAXNAMLEN], line[1024];

ULONG id, uin;

struct AsyncFile *loadfh;
struct Contact   *user;

get(obj,MUIA_UserData,&id);
get(app->STR_ICQUIN,MUIA_String_Integer,&uin);

user = GetContact(id);

sprintf(uinlog,"%sUsers/%ld/Logs/%ld",currentdir,uin,id);

DoMethod(user->UWin->LV_History,MUIM_NList_Clear);

set(user->UWin->LV_History,MUIA_NList_Quiet,TRUE);

if (loadfh = OpenAsync(uinlog,MODE_READ,AsyncBuf)) {
  while(ReadLineAsync(loadfh,line,sizeof(line)) > 0) {
    LASTCHAR(line) = '\0';
    DoMethod(user->UWin->LV_History,MUIM_NList_InsertWrap,line,-2,MUIV_NList_Insert_Bottom,WRAPCOL0,ALIGN_LEFT);
  }
  CloseAsync(loadfh);
}

set(user->UWin->LV_History,MUIA_NList_Quiet,FALSE);

return;

}


void __asm SaveHistory(REG(a2) APTR obj)

{

char uinlog[MAXNAMLEN];

int i, last = -1;

ULONG id, total, uin;

struct AsyncFile *savefh;
struct MUI_NList_GetEntryInfo res;
struct Contact *user;

get(obj,MUIA_UserData,&id);
get(app->STR_ICQUIN,MUIA_String_Integer,&uin);

sprintf(uinlog,"%sUsers/%ld/Logs/%ld",currentdir,uin,id);

user = GetContact(id);

get(user->UWin->LV_History,MUIA_NList_Entries,&total);

if (total < 1) return;

if (!(savefh = OpenAsync(uinlog,MODE_WRITE,AsyncBuf))) return;

for(i = 0; i < total; i++) {
  res.pos = i;
  DoMethod(user->UWin->LV_History,MUIM_NList_GetEntryInfo,&res);
  if (res.line == last) continue;
  WriteLineAsync(savefh,res.entry);
  WriteCharAsync(savefh,'\n');
  last = res.line;
}

CloseAsync(savefh);

SetComment(uinlog,GetNick(id));

return;

}


void __asm DeleteHistory(REG(a2) APTR obj)

{

char uinlog[MAXNAMLEN];

ULONG id, uin;

get(obj,MUIA_UserData,&id);
get(app->STR_ICQUIN,MUIA_String_Integer,&uin);

sprintf(uinlog,"%sUsers/%ld/Logs/%ld",currentdir,uin,id);

DeleteFile(uinlog);

return;

}


void __asm RemoveContact(REG(a2) APTR obj)

{

LONG sel = MUIV_NList_PrevSelected_Start, ret;

struct Contact *user;

DoMethod(app->LV_OfflineList,MUIM_NList_PrevSelected,&sel);

while(sel != MUIV_NList_PrevSelected_End) {
  DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,sel,&user);
  if (!(ret = MUI_Request(app->App,app->WI_Main,0,NULL,"Yes|Skip|Cancel","\033cDelete %s\n\nAre You Sure",user->Nick))) break;
  if (ret == 1) DeleteUIN(user->UIN);
  DoMethod(app->LV_OfflineList,MUIM_NList_PrevSelected,&sel);
}

return;

}


void DeleteUIN(ULONG uin)

{

char uinlog[MAXNAMLEN];

ULONG localin;

struct Contact *user;
struct Sockets *socks;

if (!(user = GetContact(uin))) return;

get(app->STR_ICQUIN,MUIA_String_Integer,&localin);

sprintf(uinlog,"%sUsers/%ld/Logs/%ld",currentdir,localin,user->UIN);

DeleteFile(uinlog);

sprintf(uinlog,"%sUsers/%ld/Users/%ld",currentdir,localin,user->UIN);

DeleteFile(uinlog);

if (socks = GetSocketFmContact(user,SOCK_MESSAGE)) DelSockets(socks->Socket);
if (socks = GetSocketFmContact(user,SOCK_CHAT)) DelSockets(socks->Socket);
if (socks = GetSocketFmContact(user,SOCK_FILE)) DelSockets(socks->Socket);

if (user->Status != STATUS_NEWUIN) {
  sprintf(maintitle,"STRICQ (%d)",--contacts_cnt);
  set(app->WI_Main,MUIA_Window_Title,maintitle);
}

DoMethod(app->LV_OfflineList,MUIM_NList_Remove,user->ListID);

return;

}


int recv_tcp_pkt(char *buf, struct Sockets *socks)

{

int i = 0, j = 0;

ULONG err, data;

UWORD len = 0;

if (socks->PktLen[0] == '\0' && socks->PktLen[1] == '\0') {
  i = recv(socks->Socket,buf,2,0);
//HandleError(DBG_TCP_DBUG,"Initial pkt read got %d bytes.",i);
}
else {
  i = 2;
  buf[0] = socks->PktLen[0];
  buf[1] = socks->PktLen[1];
//HandleError(DBG_OTH_INFO,"Already have the first 2, copying...");
}

if (i == 0) return(-1);

if (i > 0) {
  revmemcpy((char *)&len,buf,2);
  IoctlSocket(socks->Socket,FIONREAD,(char *)&data);
  if (data < len) {
    socks->PktLen[0] = buf[0];
    socks->PktLen[1] = buf[1];
//  HandleError(DBG_TCP_DBUG,"  Wasn't enough bytes, got %d, expecting %d.",data,len);
    return(0);
  }
  if (i != 2) {
    HandleError(DBG_TCP_ERRS,"Strange error, got %d bytes in recv_tcp_pkt.",i);
    i = 2;
  }
//PrintHex(DBG_TCP_DBUG,"buf before",buf,16);
  j = recv(socks->Socket,buf+i,len,0);
//PrintHex(DBG_TCP_DBUG,"buf after",buf,16);
}

if (i < 0 || j < 0) {
  if ((err = Errno()) != EWOULDBLOCK) {
    SocketBaseTags(SBTM_GETREF(SBTC_ERRNOSTRPTR),&err,TAG_DONE);
    HandleError(DBG_TCP_ERRS,"Error on msg/file socket %d: %s",socks->Socket,(char *)err);
    return(-1);
  }
  else {
    if (i > -1 && j < 0) {
      socks->PktLen[0] = buf[0];
      socks->PktLen[1] = buf[1];
//    HandleError(DBG_OTH_INFO,"  Got a EWOULDBLOCK, store [0],[1], return...");
    }
    return(0);
  }
}

socks->PktLen[0] = socks->PktLen[1] = '\0';

//HandleError(DBG_TCP_DBUG,"  i+j = %d",i+j);

return(i+j);

}


void ParseTCPCmd(char *buf, int len, UWORD sock)

{

BOOL *useaway, prec_flag;

char *tcpmsg, nick[50], *reply, *filename, filestats[512], *notifycmd, cmdln[MAXNAMLEN], *c;

int i, off = 0;

ULONG uin = 0, seq = 0, total = 0, index = 0, localin = 0, filesize = 0, ip = 0;

UWORD pktlen = 0, msglen = 0, cmdtype = 0, cmd = 0, msgtype = 0, status = 0, fnlen = 0, status2, port;

struct Contact *user, User;
struct ICQLog  *Logged;
struct Sockets *socks;

if (!len) return;

PrintHex(DBG_TCP_PKTS,"Incoming TCP message packet",buf,len);

get(app->STR_ICQUIN,MUIA_String_Integer,&localin);
get(app->CY_MyStatus,MUIA_Cycle_Active,&index);

if (socks = GetSocketFmSocket(sock)) {
  user = GetContact(socks->UIN);
  socks->Timehack = time(NULL);
}

status2 = TCPCodes[index];

revmemcpy((char *)&pktlen,buf+off,2); off += 2;

if (((UBYTE)buf[off] == (UBYTE)0xff) && !socks->HadInit) {
  struct TCP_Init Init;
  TCP_ParseTCPInit(&Init,buf);
  if (CheckIgnore(Init.UIN)) {
    DelSockets(socks->Socket);
    return;
  }
  if (!(user = GetContact(Init.UIN))) {
    PrepNewContact(&User);
    User.UIN = Init.UIN;
    sprintf(nick,"%ld",Init.UIN);
    User.Nick = nick;
    User.Status = STATUS_NEWUIN;
    User.CanTCP = 4;
    AddUser2CList(&User);
    user = GetContact(Init.UIN);
  }
  if (user->CanTCP != 4) user->CanTCP = 4;
  user->IP = socks->IP;
  user->Port = Init.TCP_MsgPort;
  socks->UIN = user->UIN;
  socks->Timehack = time(NULL);
  socks->HadInit = TRUE;
  DoMethod(app->LV_SockList,MUIM_NList_Redraw,MUIV_NList_Redraw_All);
//HandleError(DBG_TCP_DBUG,"Created IN entry for socket %d",sock);
}
else {
  if (!socks->HadInit) {
    HandleError(DBG_TCP_ERRS,"Got a TCP message without an init packet.  Source IP is %s.",Inet_NtoA(socks->Address.sin_addr.s_addr));
    DelSockets(socks->Socket);
    return;
  }
  revmemcpy((char *)&uin,buf+off,4); off += 4;          // UIN
  off += 2;                                             // Version (skip)
  revmemcpy((char *)&cmd,buf+off,2); off += 2;          // Msg Command
  if (cmd == TCP_MSG_UNK_2) return;
  off += 6;                                             // X1 & UIN2 (skip)
  revmemcpy((char *)&msgtype,buf+off,2); off += 2;      // Msg Type
  revmemcpy((char *)&msglen,buf+off,2); off += 2;       // Msg Len
  tcpmsg = buf+off; off += msglen;                      // Msg Text
     memcpy((char *)&ip,buf+off,4); off += 4;           // IP Real
  off += 9;                                             // IP, Port, X2 (skip)
  revmemcpy((char *)&status,buf+off,2); off += 2;       // Status
  revmemcpy((char *)&cmdtype,buf+off,2); off += 2;      // Msg Cmd Type
  switch(msgtype) {
    case TCP_MSG_MSG:
      if (len-off > 4) {
        if (*(buf+(len-3)) != 'L') {
          PrintHex(DBG_TCP_DBUG,"Unknown packet format, please report this",buf,len);
          off = len-4;
        }
      }
      break;
    case TCP_MSG_CHAT:
      revmemcpy((char *)&fnlen,buf+off,2); off += 2;    // Text Len
      filename = buf+off; off += fnlen;                 // Text
         memcpy((char *)&port,buf+off,2); off += 4;     // Port1 (Normal order)
      off += 4;                                         // Port2 (Reverse order) (skip)
      break;
    case TCP_MSG_FILE:
         memcpy((char *)&port,buf+off,2); off += 4;     // Port1 (Normal order)
      revmemcpy((char *)&fnlen,buf+off,2); off += 2;    // Filename Len
      filename = buf+off; off += fnlen;                 // Filename
      revmemcpy((char *)&filesize,buf+off,4); off += 4; // Filesize
      off += 4;                                         // Port2 (Reverse order) (skip)
      break;
  }
  revmemcpy((char *)&seq,buf+off,4); off += 4;          // Sequence
  if (!Online) {
    if (user) {
      for(i = 0; i<NUM_STATUS; i++) {
        if (TCPCodes[i] == status) {
          user->Status = Codes[i];
          break;
        }
      }
    }
  }
  if (status2 == TCP_STATUS_OCCUPIED || status2 == TCP_STATUS_DND) {
    if (cmdtype & TCP_MSG_LIST || cmdtype & TCP_MSG_URGENT) {
      if (strlen(tcpmsg)) ParseMessage(cmd,tcpmsg,uin,msgtype);
      status2 = TCP_STATUS_ONLINE;
    }
  }
  else {
    if (strlen(tcpmsg)) ParseMessage(cmd,tcpmsg,uin,msgtype);
  }
  Header.Command = cmd;
  Header.TCP_Sequence = seq;
  Header.Sequence2 = 0;
  switch(cmd) {
    case TCP_MESSAGE:
      cmdtype &= 0x007F;
      switch(cmdtype) {
        case TCP_MSG_REAL:
        case TCP_MSG_LIST:
        case TCP_MSG_URGENT:
          Add2Log(LOG_SERVER,&Header,TRUE,0,NULL);
          TCP_Seq--;
          reply = LINE;
          get(app->CY_MyStatus,MUIA_Cycle_Active,&index);
          get(app->CH_UseMessages[index],MUIA_Selected,&useaway);
          if (useaway && uin != localin) get(app->STR_Messages[index],MUIA_String_Contents,&reply);
          get(app->CH_Scrn2Frnt,MUIA_Selected,&useaway);
          switch(msgtype) {
            case TCP_MSG_MSG:
            case TCP_MSG_URL:
            case TCP_MSG_READAWAY:
            case TCP_MSG_READOCCUPIED:
            case TCP_MSG_READNA:
            case TCP_MSG_READDND:
            case TCP_MSG_READFFC:
              SendTCPMessage(uin,reply,TCP_ACK,msgtype,TCP_MSG_AUTO,seq,LINE,0x00000000,status2,0);
              break;
            case TCP_MSG_CHAT:
              if (useaway) DoMethod(app->WI_Main,MUIM_Window_ScreenToFront);
              if (strlen(filename)) sprintf(filestats,"%s\n\nMulti-Chat with:  %s",tcpmsg,filename);
              else strcpy(filestats,tcpmsg);
              CFWinOpen(uin,filestats,msgtype,seq,port);
              get(app->STR_ChatNotify,MUIA_String_Contents,&notifycmd);
              if (strlen(notifycmd) > 0) {
                sprintf(cmdln,notifycmd,uin);
                System(cmdln,NULL);
              }
              break;
            case TCP_MSG_FILE:
              if (useaway) DoMethod(app->WI_Main,MUIM_Window_ScreenToFront);
              sprintf(filestats,"Filename: %s; Filesize: %ld\n\n%s",filename,filesize,tcpmsg);
              CFWinOpen(uin,filestats,msgtype,seq,port);
              get(app->STR_FileDirect,MUIA_String_Contents,&notifycmd);
              if (strlen(notifycmd) > 0) {
                sprintf(cmdln,notifycmd,uin);
                System(cmdln,NULL);
              }
              break;
            case TCP_MSG_ADDUIN: {
              SendTCPMessage(uin,reply,TCP_ACK,msgtype,TCP_MSG_AUTO,seq,LINE,0x00000000,status2,0);
              break;
            }
            default:
              sprintf(err_buf,"Unknown message type 0x%04x.",msgtype);
              PrintHex(DBG_TCP_DBUG,err_buf,buf,len);
          }
          break;
        default:
          sprintf(err_buf,"Unknown message command type 0x%04x.",cmdtype);
          PrintHex(DBG_TCP_DBUG,err_buf,buf,len);
      }
      break;
    case TCP_ACK:
    case TCP_CANCEL:
      for(c = tcpmsg; *c; c++) if (*c == '\r') *c = ' ';
      switch(msgtype) {
        case TCP_MSG_CHAT:
          if (cmd == TCP_CANCEL) {
            HandleError(DBG_OTH_INFO,"Chat Request Canceled");
            if (user) {
              if (user->CFWin) {
//              set(user->CFWin->WI_ChatFileInWin,MUIA_Window_Open,FALSE);
//              DoMethod(app->App,OM_REMMEMBER,user->CFWin->WI_ChatFileInWin);
//              MUI_DisposeObject(user->CFWin->WI_ChatFileInWin);
//              FreeVec(user->CFWin);
//              user->CFWin = NULL;
              }
            }
          }
          else {
            if (status != TCP_STAT_ONLINE) {
              if (!strlen(tcpmsg)) tcpmsg = "No reason given.";
              HandleError(DBG_OTH_INFO,"Chat Request Refused:  %s",tcpmsg);
            }
            else {
              if (!user->ChatListen) user->ChatListen = OpenTCPListen(SOCK_CHAT);
              if (ip == 0) ip = user->IP;
              if (!user->ConnectMe) {
                if (!OpenTCPSocket(user,SOCK_CHAT,ip,port)) {
                  if (!OpenTCPSocket(user,SOCK_CHAT,user->RealIP,port)) HandleError(DBG_TCP_ERRS,"Could not open a chat connection to %s.",user->Nick);
/*                else {
                    sock2 = GetSocketFmContact(user,SOCK_CHAT);
                    SendTCPInit(sock2->Socket,user,user->ChatListen);
                    SendChatInit(sock2->Socket);
                  }
*/              }
              }
            }
          }
          break;
        case TCP_MSG_FILE:
          if (cmd == TCP_CANCEL) {
            HandleError(DBG_OTH_INFO,"File Send Canceled");
            if (user) {
              if (user->CFWin) {
//              set(user->CFWin->WI_ChatFileInWin,MUIA_Window_Open,FALSE);
//              DoMethod(app->App,OM_REMMEMBER,user->CFWin->WI_ChatFileInWin);
//              MUI_DisposeObject(user->CFWin->WI_ChatFileInWin);
//              FreeVec(user->CFWin);
//              user->CFWin = NULL;
              }
            }
          }
          else {
            if (status != TCP_STAT_ONLINE) {
              if (!strlen(tcpmsg)) tcpmsg = "No reason given.";
              HandleError(DBG_OTH_INFO,"File Transfer Refused:  %s",tcpmsg);
            }
            else {
              if (!FileListen) FileListen = OpenTCPListen(SOCK_FILE);
              if (ip == 0) ip = user->IP;
              if (!OpenTCPSocket(user,SOCK_FILE,ip,port)) {
                if (!OpenTCPSocket(user,SOCK_FILE,user->RealIP,port)) {
                  HandleError(DBG_TCP_ERRS,"Could not open a file send connection to %s.",user->Nick);
                }
              }
            }
          }
          break;
      }
      prec_flag = FALSE;
      if (cmdtype == TCP_MSG_AUTO) {
        char *buttons;
        int ret;
        UWORD prec;
        if (status == TCP_STATUS_OCCUPIED || status == TCP_STATUS_DND) {
          if (status == TCP_STATUS_OCCUPIED) buttons = "Send To Contact List|Send Urgent|Cancel";
          else buttons = "Send To Contact List|Cancel";
          if ((ret = MUI_Request(app->App,NULL,0,"Message Precedence",buttons,"User is either Occupied or set Do Not Disturb.")) == 0) break;
          prec_flag = TRUE;
          if (ret == 1) prec = TCP_MSG_LIST;
          else prec = TCP_MSG_URGENT;
          SendTCPMessage(uin,socks->LastTCP+18,TCP_MESSAGE,msgtype,prec,TCP_Seq,LINE,0x00000000,0x0000,0);
          Add2Log(LOG_CLIENT,&Header,FALSE,0,NULL);
        }
      }
      if (!prec_flag) {
        if (socks) {
          if (socks->LastTCP) {
            FreeVec(socks->LastTCP);
            socks->LastTCP = NULL;
          }
        }
        if (user->UWin) {
          set(user->UWin->BB_WaitTCP,MUIA_Busy_Speed,MUIV_Busy_Speed_Off);
          set(user->UWin->BB_WaitTCP,MUIA_ShowMe,FALSE);
        }
      }
      get(app->LV_ICQCliLog,MUIA_NList_Entries,&total);
      for(i = total-1; i>-1; i--) {
        DoMethod(app->LV_ICQCliLog,MUIM_NList_GetEntry,i,&Logged);
        if (Logged) {
//        HandleError(DBG_TCP_DBUG,"Logged->Seq = %ld, Header.TCP_Sequence = %ld",Logged->Seq,Header.TCP_Sequence);
          if (Logged->Seq == Header.TCP_Sequence) {
            Logged->Ack = TRUE;
            DoMethod(app->LV_ICQCliLog,MUIM_NList_Redraw,i);
            break;
          }
        }
      }
      break;
    default:
      sprintf(err_buf,"Unknown message command 0x%04x.",cmd);
      PrintHex(DBG_TCP_DBUG,err_buf,buf,len);
  }
}

return;

}


BOOL SendTCPMessage(ULONG to, char *msg, UWORD cmd, UWORD type, UWORD cmdtype, ULONG seq, char *filename, ULONG filesize, UWORD status, ULONG port2)

{

char buf[2048];

LONG ret = 1;

UBYTE x2;

ULONG uin = 0, port, addr, index;

UWORD len = 0, ver, x1, msglen, revlen, fnlen, port3;

UWORD MsgStatus[] = {TCP_MSG_REAL, TCP_MSGF_S_INVISIBLE, TCP_MSGF_S_NA, TCP_MSG_REAL, TCP_MSGF_S_OCCUPIED, TCP_MSGF_S_AWAY, TCP_MSGF_S_DND, TCP_MSG_REAL};

struct Contact *User;
struct Sockets *socks;

if (!(User = GetContact(to))) return(FALSE);

if (!(socks = GetSocketFmContact(User,SOCK_MESSAGE))) {
  if (User->CanTCP != 4) return(FALSE);
  if (!(ret = OpenTCPSocket(User,SOCK_MESSAGE,User->IP,User->Port))) {
    if (!(ret = OpenTCPSocket(User,SOCK_MESSAGE,User->RealIP,User->Port))) return(FALSE);
  }
  socks = GetSocketFmContact(User,SOCK_MESSAGE);
  if (User->Status & STATUSF_HIDEIP) socks->Hidden = TRUE;
  if (ret != -1) SendTCPInit(socks->Socket,User,0);
}

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);
get(app->CY_MyStatus,MUIA_Cycle_Active,&index);

if (cmdtype != TCP_MSG_AUTO) {
  MsgStatus[0] = MsgStatus[3] = MsgStatus[7] = cmdtype;
  cmdtype |= MsgStatus[index];
}

ver = 0x0002;
x1 = 0x0000;
msglen = strlen(msg)+1;
fnlen = strlen(filename)+1;
port = socks->LocalAddr.sin_port;
addr = socks->LocalAddr.sin_addr.s_addr;
x2 = 0x02;
port3 = port2;

revmemcpy(buf+len,(char *)&uin,4); len += 4;
revmemcpy(buf+len,(char *)&ver,2); len += 2;
revmemcpy(buf+len,(char *)&cmd,2); len += 2;
revmemcpy(buf+len,(char *)&x1,2); len += 2;
revmemcpy(buf+len,(char *)&uin,4); len += 4;
revmemcpy(buf+len,(char *)&type,2); len += 2;
revmemcpy(buf+len,(char *)&msglen,2); len += 2;
strcpy   (buf+len,msg); len += msglen;
   memcpy(buf+len,(char *)&addr,4); len += 4;
   memcpy(buf+len,(char *)&addr,4); len += 4;
revmemcpy(buf+len,(char *)&port,4); len += 4;
revmemcpy(buf+len,(char *)&x2,1); len++;
revmemcpy(buf+len,(char *)&status,2); len += 2;
revmemcpy(buf+len,(char *)&cmdtype,2); len += 2;

switch(type) {
  case TCP_MSG_CHAT:
    revmemcpy(buf+len,(char *)&fnlen,2); len += 2;
    strcpy   (buf+len,filename); len += fnlen;
       memcpy(buf+len,(char *)&port3,2); len += 2;
    revmemcpy(buf+len,(char *)&x1,2); len += 2;
    revmemcpy(buf+len,(char *)&port2,4); len += 4;
    break;
  case TCP_MSG_FILE:
       memcpy(buf+len,(char *)&port3,2); len += 2;
    revmemcpy(buf+len,(char *)&x1,2); len += 2;
    revmemcpy(buf+len,(char *)&fnlen,2); len += 2;
    strcpy   (buf+len,filename); len += fnlen;
    revmemcpy(buf+len,(char *)&filesize,4); len += 4;
    revmemcpy(buf+len,(char *)&port2,4); len += 4;
    break;
}

revmemcpy(buf+len,(char *)&seq,4); len += 4;

PrintHex(DBG_TCP_PKTS,"Outgoing TCP message packet",buf,len);

if (cmd != TCP_ACK) {
  if (!socks->LastTCP) {
    if (!(socks->LastTCP = AllocVec(len,MEMF_CLEAR))) {
      HandleError(DBG_OTH_FATL,"Could not allocate %d bytes.",len);
      return(FALSE);
    }
    memcpy(socks->LastTCP,buf,len);
    socks->TCPLen = len;
  }
  if (User->UWin) {
    set(User->UWin->BB_WaitTCP,MUIA_ShowMe,TRUE);
    set(User->UWin->BB_WaitTCP,MUIA_Busy_Speed,MUIV_Busy_Speed_User);
  }
}

if (ret == -1) return(TRUE);

revmemcpy((char *)&revlen,(char *)&len,2);

send(socks->Socket,(char *)&revlen,2,0);
send(socks->Socket,buf,len,0);

socks->Timehack = time(NULL);

return(TRUE);

}


LONG OpenTCPSocket(struct Contact *user, UBYTE type, ULONG ip, ULONG port)

{

LONG size = 1, ret = TRUE;

struct Sockets Socks;
struct timeval tv;

//HandleError(DBG_TCP_DBUG,"%s:%ld",Inet_NtoA(ip),port);

if (ip == 0 || port == 0) return(FALSE);

memset(&Socks.Address,NULL,sizeof(struct sockaddr));
memset(&Socks.LocalAddr,NULL,sizeof(struct sockaddr));

Socks.Address.sin_addr.s_addr = ip;
Socks.Address.sin_len = sizeof(struct sockaddr_in);

if ((Socks.Socket = socket(AF_INET,SOCK_STREAM,0)) == -1) {
  HandleError(DBG_TCP_ERRS,"Could not create a TCP socket.");
  return(FALSE);
}

if (Socks.Socket > maxfd) maxfd = Socks.Socket;

FD_SET(Socks.Socket,&rset);
FD_SET(Socks.Socket,&wset);

Socks.Address.sin_family = AF_INET;
Socks.Address.sin_port = port;

if (IoctlSocket(Socks.Socket,FIOASYNC,(char *)&size) == -1) {
  HandleError(DBG_TCP_ERRS,"Error in IoctlSocket FIOASYNC for TCP socket.");
  return(FALSE);
}

if (IoctlSocket(Socks.Socket,FIONBIO,(char *)&size) == -1) {
  HandleError(DBG_TCP_ERRS,"Error in IoctlSocket FIONBIO for TCP socket.");
  return(FALSE);
}

tv.tv_sec = 45;
tv.tv_usec = 0;

if (setsockopt(Socks.Socket,SOL_SOCKET,SO_SNDTIMEO,&tv,sizeof(tv)) == -1) {
  HandleError(DBG_TCP_ERRS,"Could not setsockopt SO_SNDTIMEO for TCP socket.");
}

size = FILE_PKT_SIZE*2;

if (setsockopt(Socks.Socket,SOL_SOCKET,SO_SNDLOWAT,&size,sizeof(size)) == -1) {
  HandleError(DBG_TCP_ERRS,"Could not setsockopt SO_SNDLOWAT for TCP socket.");
}

if (connect(Socks.Socket,(struct sockaddr *)&Socks.Address,sizeof(Socks.Address)) == -1) {
  if (Errno() != EINPROGRESS) return(FALSE);
  else ret = -1;
}

Socks.UIN = user->UIN;
Socks.Dir = TCP_DIR_OUT;
Socks.IP = ip;
Socks.Port = port;
Socks.TCPLen = 0;
Socks.LastTCP = NULL;
Socks.ChatMode = Socks.FileMode = NULL;
Socks.RCObj = NULL;
Socks.Timehack = time(NULL);
Socks.Type = type;
Socks.HadInit = Socks.Hidden = Socks.Backward = Socks.Closing = FALSE;
Socks.CWin = NULL;
Socks.PktLen[0] = Socks.PktLen[1] = '\0';

if (ret == -1) Socks.Connecting = TRUE;
else Socks.Connecting = FALSE;

DoMethod(app->LV_SockList,MUIM_NList_InsertSingle,&Socks,MUIV_NList_Insert_Sorted);

//HandleError(DBG_TCP_DBUG,"created OUT entry for socket %d",Socks.Socket);

return(ret);

}


void SendTCPInit(UWORD sock, struct Contact *User, ULONG port)

{

char buf[256];

UBYTE ident, x3;

ULONG x1, uin, addr, port2;

UWORD revlen, len = 0;

struct Sockets *socks;

get(app->STR_ICQUIN,MUIA_String_Integer,&uin);

socks = GetSocketFmSocket(sock);

if (socks->HadInit) {
  HandleError(DBG_TCP_DBUG,"Aborting extraneous TCPInit for socket %d",sock);
  return;
}

HandleError(DBG_TCP_DBUG,"Sending TCPInit for socket %d",sock);

ident = 0xff;
x1 = 0x00000002;
addr = socks->LocalAddr.sin_addr.s_addr;
if (!port) port2 = socks->LocalAddr.sin_port;
x3 = 0x04;

revmemcpy(buf+len,(char *)&ident,1); len++;
revmemcpy(buf+len,(char *)&x1,4); len += 4;
revmemcpy(buf+len,(char *)&port,4); len += 4;
revmemcpy(buf+len,(char *)&uin,4); len += 4;
   memcpy(buf+len,(char *)&addr,4); len += 4;
   memcpy(buf+len,(char *)&addr,4); len += 4;
revmemcpy(buf+len,(char *)&x3,1); len++;
revmemcpy(buf+len,(char *)&port2,4); len += 4;

revmemcpy((char *)&revlen,(char *)&len,2);

send(sock,(char *)&revlen,2,0);
send(sock,buf,len,0);

if (socks->LastTCP) {
  revmemcpy((char *)&revlen,(char *)&socks->TCPLen,2);
  send(sock,(char *)&revlen,2,0);
  send(sock,socks->LastTCP,socks->TCPLen,0);
  socks->Timehack = time(NULL);
}

socks->HadInit = TRUE;

return;

}


void PrepNewContact(struct Contact *user)

{

memset((char *)user,0,sizeof(struct Contact));

user->Country = user->Age = 0xffff;

user->Type = TCP_MSG_MSG;

user->Status = STATUS_OFFLINE;

return;

}


APTR __asm AddSock(REG(a2) APTR pool, REG(a1) struct Sockets *socks)

{

struct Sockets *newsocks = NULL;

if (!(newsocks = AllocPooled(pool,sizeof(struct Sockets)))) return(NULL);

newsocks->Socket = socks->Socket;
newsocks->UIN = socks->UIN;
newsocks->Dir = socks->Dir;
newsocks->IP = socks->IP;
newsocks->Port = socks->Port;
newsocks->TCPLen = socks->TCPLen;
newsocks->LastTCP = socks->LastTCP;
newsocks->Timehack = socks->Timehack;
newsocks->Connecting = socks->Connecting;
newsocks->ChatMode = socks->ChatMode;
newsocks->FileMode = socks->FileMode;
newsocks->HadInit = socks->HadInit;
newsocks->Backward = socks->Backward;
newsocks->Hidden = socks->Hidden;
newsocks->Type = socks->Type;
newsocks->Closing = socks->Closing;
newsocks->PktLen[0] = newsocks->PktLen[1] = '\0';
newsocks->TCP_Version = socks->TCP_Version;
newsocks->TCP_Revision = socks->TCP_Revision;
newsocks->TCP_Listen_Msg_Port = socks->TCP_Listen_Msg_Port;
newsocks->TCP_Listen_Other_Port = socks->TCP_Listen_Other_Port;
newsocks->TCP_ChatData = socks->TCP_ChatData;
newsocks->RCObj = socks->RCObj;
newsocks->ConnectPort = socks->ConnectPort;
newsocks->CWin = socks->CWin;

memcpy((char *)&newsocks->Address,(char *)&socks->Address,sizeof(socks->Address));
memcpy((char *)&newsocks->LocalAddr,(char *)&socks->LocalAddr,sizeof(socks->LocalAddr));

return(newsocks);

}


void __asm RemSock(REG(a2) APTR pool, REG(a1) struct Sockets *newsocks)

{

if (newsocks->LastTCP) FreeVec(newsocks->LastTCP);
if (newsocks->RCObj) FreeVec(newsocks->RCObj);
if (newsocks->CWin) FreeVec(newsocks->CWin);

FreePooled(pool,newsocks,sizeof(struct Sockets));

return;

}


LONG __asm CmpSock(REG(a1) struct Sockets *s1, REG(a2) struct Sockets *s2)

{

if (s1->Socket < s2->Socket) return(-1);
if (s1->Socket > s2->Socket) return(1);

return(0);

}


void __asm DisplaySock(REG(a2) char **array, REG(a1) struct Sockets *socks)

{

static char sock[5], dir[7], ip[25], type[16];

if (socks) {
  sprintf(sock,"%d",socks->Socket);
  switch(socks->Dir) {
    case TCP_DIR_IN:
      strcpy(dir,"In");
      break;
    case TCP_DIR_OUT:
      strcpy(dir,"Out");
      break;
    case TCP_DIR_LISTEN:
      strcpy(dir,"Listen");
      break;
  }
  if (!socks->Hidden) sprintf(ip,"%s:%d",Inet_NtoA(socks->IP),socks->Port);
  else strcpy(ip,"Hidden");
  switch(socks->Type) {
    case SOCK_UDP:
      strcpy(type,"UDP");
      break;
    case SOCK_MESSAGE:
      strcpy(type,"Message");
      break;
    case SOCK_CHAT:
      strcpy(type,"Chat");
      break;
    case SOCK_FILE:
      strcpy(type,"File");
      break;
  }
  *array++ = sock;
  *array++ = GetNick(socks->UIN);
  *array++ = dir;
  *array++ = ip;
  *array   = type;
}
else {
  *array++ = "Socket";
  *array++ = "Nick";
  *array++ = "Dir";
  *array++ = "IP:Port";
  *array   = "Type";
}

return;

}


void DelSockets(UWORD sock)

{

BOOL flag = TRUE;

char msg[512];

int i;

LONG total;

struct Contact *user;
struct Sockets *socks;

get(app->LV_SockList,MUIA_NList_Entries,&total);

for(i = 0; i < total; i++) {
  DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  if (socks) {
    if (socks->Socket == sock) {
      user = GetContact(socks->UIN);
      if (socks->LastTCP) {
        if (Online) {
          if (user) {
            strcpy(msg,socks->LastTCP+18);
            DoMethod(app->LV_SockList,MUIM_NList_Remove,i);
            flag = FALSE;
            SendAMessage(NULL,user->UIN,msg,0x0001,MSG_REMOTE,MSG_VIA_UDP);
            if (user->UWin) {
              set(user->UWin->BB_WaitTCP,MUIA_Busy_Speed,MUIV_Busy_Speed_Off);
              set(user->UWin->BB_WaitTCP,MUIA_ShowMe,FALSE);
            }
            if (socks->RCObj) EndChat(socks->RCObj->GP_RemoteObj);
//          HandleError(DBG_TCP_DBUG,"TCP message being sent via UDP (%s)",user->Nick);
//          HandleError(DBG_TCP_DBUG,"%s",msg);
          }
        }
      }
      if (flag) DoMethod(app->LV_SockList,MUIM_NList_Remove,i);
      break;
    }
  }
}

FD_CLR(sock,&rset);
FD_CLR(sock,&wset);

//HandleError(DBG_TCP_DBUG,"Closing socket %d",sock);

CloseSocket(sock);

return;

}


char *FindCountryName(UWORD code)

{

int i = -1;

while(CountryCodes[++i] != 0) if (code == CountryCodes[i]) break;

return(CountryNames[i]);

}


void SendMessage2Script(char *msg, ULONG uin, UWORD type)

{

char *notifycmd, cmdln[MAXNAMLEN];

struct AsyncFile *savefh;

get(app->STR_MsgParse,MUIA_String_Contents,&notifycmd);

if (!strlen(notifycmd)) return;

tmpnam(tmpmsg_fl);

if (!(savefh = OpenAsync(tmpmsg_fl,MODE_WRITE,AsyncBuf))) return;
WriteLineAsync(savefh,msg);
CloseAsync(savefh);

sprintf(cmdln,"%s %ld %d %s",notifycmd,uin,type,tmpmsg_fl);

System(cmdln,NULL);

return;

}


void AddUser2CList(struct Contact *user)

{

static ULONG lampnum = 0;

sprintf(user->LampTxt,"\033o[%ld]",lampnum);

user->LampNum = lampnum;

if (WhichLamp == 0) {
  user->LampObj = LampObject, End;
}
else {
  user->LampObj = TWFmultiLEDObject, End;
}

DoMethod(app->LV_OfflineList,MUIM_NList_UseImage,user->LampObj,lampnum++,0L);

DoMethod(app->LV_OfflineList,MUIM_NList_InsertSingle,user,MUIV_NList_Insert_Bottom);

return;

}


void CFWinOpen(ULONG uin, char *msg, UWORD mode, LONG seq, UWORD port)

{

char *c, *d;

static char title[25];

int i;

ULONG total;

struct ChatSession *session;
struct ChatFileReqIn *CFWin;
struct Contact *user;

if (!(user = GetContact(uin))) return;

if (user->CFWin) {
  set(user->CFWin->WI_ChatFileInWin,MUIA_Window_Open,TRUE);
  return;
}

if (!(CFWin = AllocVec(sizeof(struct ChatFileReqIn),MEMF_CLEAR))) {
  HandleError(DBG_OTH_FATL,"Failed to AllocVec %d bytes!",sizeof(struct ChatFileReqIn));
  return;
}

for(c = d = msg; *c; c++, d++) {
  if (*c == '\r') c++;
  *d = *c;
}
*d = '\0';

if (mode == TCP_MSG_CHAT) strcpy(title,"Reason For Chat Request");
else strcpy(title,"Reason For File Transfer");

CFWin->WI_ChatFileInWin = WindowObject,
  MUIA_Window_Title, user->Nick,
  MUIA_Window_CloseGadget, FALSE,
  MUIA_Window_ID, uin | 0x10000000,
  MUIA_UserData, seq,
  WindowContents, VGroup,
    Child, CFWin->GP_Message = GroupObject,
      MUIA_UserData, port,
      MUIA_Frame, MUIV_Frame_Group,
      MUIA_FrameTitle, title,
      Child, CFWin->TX_Request = TextObject,
        MUIA_Background, MUII_TextBack,
        MUIA_Frame, MUIV_Frame_Text,
        MUIA_Text_PreParse, "\033c",
        MUIA_Text_Contents, msg,
        MUIA_UserData, mode,
      End,
      Child, CFWin->LV_Sessions = NListviewObject,
        MUIA_NListview_NList, NListObject,
          MUIA_Frame, MUIV_Frame_String,
          MUIA_CycleChain, TRUE,
          MUIA_NList_Title, TRUE,
          MUIA_NList_Format, "BAR,",  //Port, Nicks
          MUIA_NList_CompareHook,   &CmpSessionHook,
          MUIA_NList_ConstructHook, &AddSessionHook,
          MUIA_NList_DestructHook,  &RemSessionHook,
          MUIA_NList_DisplayHook,   &DisplaySessionHook,
        End,
      End,
    End,
    Child, VGroup,
      MUIA_Frame, MUIV_Frame_Group,
      MUIA_FrameTitle, "Your Reason For Refusal",
      Child, CFWin->TI_Reason = TextinputObject,
        MUIA_Frame, MUIV_Frame_String,
        MUIA_CycleChain, TRUE,
        MUIA_Textinput_Multiline, TRUE,
        MUIA_Textinput_Contents, NULL,
        MUIA_Textinput_MaxLen, 512,
      End,
    End,
    Child, HGroup,
      Child, CFWin->BT_Accept = SimpleButton("Accept"),
      Child, CFWin->BT_Join   = SimpleButton("Join"),
      Child, HSpace(0),
      Child, CFWin->BT_Refuse = SimpleButton("Refuse"),
    End,
  End,
End;

if (!CFWin->WI_ChatFileInWin) {
  HandleError(DBG_OTH_FATL,"Could not create the chat/file response request window.");
  FreeVec(CFWin);
  CFWin = NULL;
  return;
}

user->CFWin = CFWin;

DoMethod(app->App,OM_ADDMEMBER,CFWin->WI_ChatFileInWin);

set(CFWin->BT_Accept,MUIA_UserData,uin);
set(CFWin->BT_Accept,MUIA_CycleChain,TRUE);
set(CFWin->BT_Refuse,MUIA_UserData,uin);
set(CFWin->BT_Refuse,MUIA_CycleChain,TRUE);
set(CFWin->BT_Join,MUIA_UserData,uin);
set(CFWin->BT_Join,MUIA_CycleChain,TRUE);

DoMethod(CFWin->BT_Accept, MUIM_Notify, MUIA_Pressed, FALSE, CFWin->BT_Accept, 2,
         MUIM_CallHook, &AcceptHook);

DoMethod(CFWin->BT_Join, MUIM_Notify, MUIA_Pressed, FALSE, CFWin->BT_Join, 2,
         MUIM_CallHook, &AcceptHook);

DoMethod(CFWin->BT_Refuse, MUIM_Notify, MUIA_Pressed, FALSE, CFWin->BT_Refuse, 2,
         MUIM_CallHook, &RefuseHook);

get(app->LV_Sessions,MUIA_NList_Entries,&total);

if (port != 0 || total == 0 || mode != MSG_CHAT) {
  set(CFWin->LV_Sessions,MUIA_ShowMe,FALSE);
  set(CFWin->BT_Join,MUIA_ShowMe,FALSE);
}
else {
  for(i = 0; i < total; i++) {
    DoMethod(app->LV_Sessions,MUIM_NList_GetEntry,i,&session);
    if (session) DoMethod(CFWin->LV_Sessions,MUIM_NList_InsertSingle,session,MUIV_NList_Insert_Sorted);
  }
  set(CFWin->LV_Sessions,MUIA_ShowMe,TRUE);
  set(CFWin->BT_Join,MUIA_ShowMe,TRUE);
}

set(CFWin->WI_ChatFileInWin,MUIA_Window_Open,TRUE);

return;

}


void __asm Accept(REG(a2) APTR obj)

{

LONG seq, sel;

ULONG uin, mode, port;

struct ChatSession *chat;
struct Contact *user;

get(obj,MUIA_UserData,&uin);

if (!(user = GetContact(uin))) return;

get(user->CFWin->GP_Message,MUIA_UserData,&port);
get(user->CFWin->TX_Request,MUIA_UserData,&mode);
get(user->CFWin->WI_ChatFileInWin,MUIA_UserData,&seq);

if (obj == user->CFWin->BT_Join) {
  get(user->CFWin->LV_Sessions,MUIA_NList_Active,&sel);
  if (sel == MUIV_NList_Active_Off) {
    HandleError(DBG_OTH_FATL,"You must choose a chat session to 'Join'.");
    return;
  }
  DoMethod(user->CFWin->LV_Sessions,MUIM_NList_GetEntry,sel,&chat);
  if (chat) user->ChatListen = chat->ChatListen;
}

set(user->CFWin->WI_ChatFileInWin,MUIA_Window_Open,FALSE);

if (mode == TCP_MSG_CHAT) {
  if (!user->ChatListen) user->ChatListen = OpenTCPListen(SOCK_CHAT);
  if (port) {
    HandleError(DBG_TCP_DBUG,"While accepting chat, port = %d",port);
    if (!OpenTCPSocket(user,SOCK_CHAT,user->IP,port)) {
      if (!OpenTCPSocket(user,SOCK_CHAT,user->RealIP,port)) HandleError(DBG_TCP_ERRS,"Could not open a chat connection to %s.",user->Nick);
    }
  }
  SendTCPMessage(uin,LINE,TCP_ACK,mode,TCP_MSG_AUTO,seq,LINE,0x00000000,TCP_STAT_ONLINE,user->ChatListen);
}
else {
  if (!FileListen) FileListen = OpenTCPListen(SOCK_FILE);
  SendTCPMessage(uin,LINE,TCP_ACK,mode,TCP_MSG_AUTO,seq,LINE,0x00000000,TCP_STAT_ONLINE,FileListen);
}

//DoMethod(app->App,OM_REMMEMBER,user->CFWin->WI_ChatFileInWin);

//MUI_DisposeObject(user->CFWin->WI_ChatFileInWin);

//FreeVec(user->CFWin);

//user->CFWin = NULL;

user->Type = mode;

return;

}


void __asm Refuse(REG(a2) APTR obj)

{

char *msg;

LONG seq;

ULONG uin, mode;

struct Contact *user;

get(obj,MUIA_UserData,&uin);

if (!(user = GetContact(uin))) return;

get(user->CFWin->TX_Request,MUIA_UserData,&mode);
get(user->CFWin->WI_ChatFileInWin,MUIA_UserData,&seq);
get(user->CFWin->TI_Reason,MUIA_Textinput_Contents,&msg);

SendTCPMessage(uin,msg,TCP_ACK,mode,TCP_MSG_AUTO,seq,LINE,0x00000000,TCP_STAT_REFUSE,0);

set(user->CFWin->WI_ChatFileInWin,MUIA_Window_Open,FALSE);

//DoMethod(app->App,OM_REMMEMBER,user->CFWin->WI_ChatFileInWin);

//MUI_DisposeObject(user->CFWin->WI_ChatFileInWin);

//FreeVec(user->CFWin);

//user->CFWin = NULL;

return;

}


APTR __asm AddCols(REG(a2) APTR pool, REG(a1) struct Column *col)

{

struct Column *newcol = NULL;

if (!(newcol = AllocPooled(pool,sizeof(struct Column)))) return(NULL);

if (!(newcol->Name = AllocPooled(pool,strlen(col->Name)+1))) {
  FreePooled(pool,newcol,sizeof(struct Column));
  return(NULL);
}
strcpy(newcol->Name,col->Name);

if (!(newcol->COL = AllocPooled(pool,strlen(col->COL)+1))) {
  FreePooled(pool,newcol->Name,strlen(newcol->Name)+1);
  FreePooled(pool,newcol,sizeof(struct Column));
  return(NULL);
}
strcpy(newcol->COL,col->COL);

return(newcol);

}


void __asm RemCols(REG(a2) APTR pool, REG(a1) struct Column *newcol)

{

FreePooled(pool,newcol->Name,strlen(newcol->Name)+1);
FreePooled(pool,newcol->COL,strlen(newcol->COL)+1);
FreePooled(pool,newcol,sizeof(struct Column));

return;

}


LONG __asm CmpCols(REG(a1) struct Column *c1, REG(a2) struct Column *c2)

{

return(strcmp(c1->Name,c2->Name));

}


void __asm DisplayCols(REG(a2) char **array, REG(a1) struct Column *col)

{

if (col) {
  *array = col->Name;
}
else {
  *array = "Columns";
}

return;

}


ULONG __asm ColsDispatcher(REG(a0) struct IClass *cl, REG(a2) Object *obj, REG(a1) Msg msg)

{

switch(msg->MethodID) {
  case MUIM_DragQuery:
    return(COLS_mDragQuery(cl,obj,(APTR)msg));
  case MUIM_DragDrop:
    return(COLS_mDragDrop(cl,obj,(APTR)msg));
}

return(DoSuperMethodA(cl,obj,msg));

}


ULONG COLS_mDragQuery(struct IClass *cl, Object *obj, struct MUIP_DragDrop *msg)

{

if (msg->obj == obj) return(DoSuperMethodA(cl,obj,(Msg)msg));
else {
  if (msg->obj == (Object *)muiUserData(obj)) return(MUIV_DragQuery_Accept);
  else return(MUIV_DragQuery_Refuse);
}

}


ULONG COLS_mDragDrop(struct IClass *cl, Object *obj, struct MUIP_DragDrop *msg)

{

APTR entry, parent;

LONG dropmark, sortable;

ULONG ret = 0;

if (obj == app->LV_StoreUser) parent = app->LV_ColsStore;
else parent = app->LV_ColsUse;

if (msg->obj == obj) ret = DoSuperMethodA(cl,obj,(Msg)msg);
else {
  DoMethod(msg->obj,MUIM_NList_GetEntry,MUIV_NList_GetEntry_Active,&entry);
  get(obj,MUIA_NList_DragSortable,&sortable);
  if (sortable) {
    get(obj,MUIA_NList_DropMark,&dropmark);
    DoMethod(parent,MUIM_NList_InsertSingle,entry,dropmark);
  }
  else DoMethod(parent,MUIM_NList_InsertSingle,entry,MUIV_NList_Insert_Sorted);
  DoMethod(msg->obj,MUIM_NList_Remove,MUIV_NList_Remove_Active);
  get(obj,MUIA_NList_InsertPosition,&dropmark);
  set(obj,MUIA_NList_Active,dropmark);
  set(msg->obj,MUIA_List_Active,MUIV_NList_Active_Off);
}

ReDrawCList();

return(ret);

}


void ReDrawCList(void)

{

char format[100];

int i;

LONG total;

struct Column *col;

format[0] = '\0';

get(app->LV_ColsUse,MUIA_NList_Entries,&total);

for(i = 0; i < total; i++) {
  DoMethod(app->LV_ColsUse,MUIM_NList_GetEntry,i,&col);
  strcat(format,col->COL);
  if (i < total-1) strcat(format," BAR,");
}

set(app->LV_OfflineList,MUIA_NList_Format,format);

return;

}


APTR __asm AddIgnore(REG(a2) APTR pool, REG(a1) struct IgnoreUIN *ignore)

{

struct IgnoreUIN *newignore = NULL;

if (!(newignore = AllocPooled(pool,sizeof(struct IgnoreUIN)))) return(NULL);

newignore->UIN = ignore->UIN;
newignore->Timehack = ignore->Timehack;
newignore->ExpireDays = ignore->ExpireDays;

strcpy(newignore->Nick,ignore->Nick);

return(newignore);

}


void __asm RemIgnore(REG(a2) APTR pool, REG(a1) struct IgnoreUIN *newignore)

{

FreePooled(pool,newignore,sizeof(struct IgnoreUIN));

return;

}


LONG __asm CmpIgnore(REG(a1) struct IgnoreUIN *i1, REG(a2) struct IgnoreUIN *i2)

{

if (i1->UIN < i2->UIN) return(-1);
if (i1->UIN > i2->UIN) return(1);

return(0);

}


void __asm DisplayIgnore(REG(a2) char **array, REG(a1) struct IgnoreUIN *ignore)

{

static char uin[32], tme[32], days[32];

struct tm *time_p;

if (ignore) {
  sprintf(uin,"%ld",ignore->UIN);
  time_p = localtime(&ignore->Timehack);
  strftime(tme,sizeof(tme),"%d %b %Y",time_p);
  if (ignore->ExpireDays == 0) strcpy(days,"Never Expire");
  else sprintf(days,"%d Days Remaining.",(ignore->ExpireDays-time(NULL))/86400);
  *array++ = uin;
  *array++ = ignore->Nick;
  *array++ = tme;
  *array   = days;
}
else {
  *array++ = "Ignored UIN";
  *array++ = "Nick";
  *array++ = "Date Ignored";
  *array   = "Days Remaining Ignored";
}

return;

}


void __asm Add2Ignore(REG(a2) APTR obj)

{

char uin_str[32];

ULONG uin;

if (obj == app->BT_AddIgnore) get(app->STR_UIN2Ignore,MUIA_String_Integer,&uin);
else get(obj,MUIA_UserData,&uin);

sprintf(uin_str,"%ld",uin);

set(app->TX_IgnoreUIN,MUIA_Text_Contents,uin_str);
set(app->TX_IgnoreNick,MUIA_Text_Contents,GetNick(uin));
set(app->NU_IgnoreDays,MUIA_Numeric_Value,30);

set(app->BT_IgnoreOK,MUIA_UserData,uin);

set(app->WI_EditIgnore,MUIA_Window_Open,TRUE);

return;

}


BOOL CheckIgnore(ULONG uin)

{

int i;

ULONG total;

struct IgnoreUIN *ignore;

get(app->LV_IgnoreUIN,MUIA_NList_Entries,&total);

if (total) {
  for(i = 0; i < total; i++) {
    DoMethod(app->LV_IgnoreUIN,MUIM_NList_GetEntry,i,&ignore);
    if (ignore) {
      if (ignore->UIN == uin) return(TRUE);
    }
  }
}

return(FALSE);

}


void Add2Log(UBYTE list, struct UDP_Header *Header, BOOL ack, UWORD len, char *pkt)


{

APTR LogList;

struct ICQLog Log;

Log.UIN = Header->UIN;
if (Header->Command == TCP_MESSAGE) Log.Seq = Header->TCP_Sequence;
else Log.Seq = Header->Sequence;
Log.Se2 = Header->Sequence2;
Log.Cmd = Header->Command;
Log.Ack = ack;
Log.Len = len;
Log.Pkt = pkt;
Log.Resend = 0;
Log.Timehack = time(NULL);

switch(list) {
  case LOG_CLIENT:
    LogList = app->LV_ICQCliLog;
    if (Log.Cmd != C_KEEP_ALIVE) LastSend = time(NULL);
    break;
  case LOG_SERVER:
    LogList = app->LV_ICQSrvLog;
    break;
}

DoMethod(LogList,MUIM_NList_InsertSingle,&Log,MUIV_NList_Insert_Bottom);


return;

}


void __asm ForwardMsg(REG(a2) APTR obj)

{

char *msg2;

LONG pos, sel = MUIV_NList_NextSelected_Start;

ULONG uin;

struct Contact    *user;
struct ICQMessage *msg, *desc;

get(obj,MUIA_UserData,&uin);

if (!(user = GetContact(uin))) return;

get(user->UWin->LV_Msgs,MUIA_NList_Active,&pos);

if (pos < 0) return;

DoMethod(user->UWin->LV_Msgs,MUIM_NList_GetEntry,pos,&msg);

if (msg->UIN == 0 && msg->Type != MSG_URL) return;

if (!(msg2 = AllocVec(strlen(msg->Msg)+0x100,MEMF_CLEAR))) return;

if (msg->Type == MSG_URL) {
  DoMethod(user->UWin->LV_Msgs,MUIM_NList_GetEntry,pos-1,&desc);
  sprintf(msg2,"Forwarded from %s: %s\xFE%s",GetNick(uin),desc->Msg,msg->Msg+2);
}
else sprintf(msg2,"Forwarded from %s: %s",GetNick(uin),msg->Msg);

DoMethod(app->LV_OfflineList,MUIM_NList_NextSelected,&sel);

while(sel != MUIV_NList_NextSelected_End) {
  DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,sel,&user);
  if (user->UIN != uin) SendAMessage(obj,user->UIN,msg2,msg->Type,MSG_BOTH,MSG_VIA_BEST);
  DoMethod(app->LV_OfflineList,MUIM_NList_NextSelected,&sel);
}

FreeVec(msg2);

return;

}


char *PreParseMsg(ULONG uin, UWORD type, char *msg)

{

char cmdln[MAXNAMLEN], *cmd;

struct AsyncFile *savefh;

get(app->STR_MsgPreParse,MUIA_String_Contents,&cmd);

if (!strlen(cmd)) return(msg);

tmpnam(tmpmsg_fl);

if (!(savefh = OpenAsync(tmpmsg_fl,MODE_WRITE,AsyncBuf))) return(msg);
WriteLineAsync(savefh,msg);
CloseAsync(savefh);

sprintf(cmdln,"%s %ld %d %s",cmd,uin,type,tmpmsg_fl);

System(cmdln,NULL);

return(LINE);

}


void __asm SetCountry(REG(a2) APTR obj)

{

APTR List, String;

char *country, tmp[128];

ULONG entry;

if (obj == app->POP_Country) {
  List = app->LV_Countries;
  String = app->STR_Country;
}
else {
  List = app->LV_WkCountries;
  String = app->STR_WkCountry;
}

get(List,MUIA_NList_EntryClick,&entry);

DoMethod(List,MUIM_NList_GetEntry,entry,&country);

sprintf(tmp,"%d %s",CountryCodes[entry],country);

set(String,MUIA_String_Contents,tmp);
set(String,MUIA_UserData,CountryCodes[entry]);

return;

}


UWORD MakeBeats(time_t time_norm)

{

float beatf;

LONG time_zone;

time_t t1;

ULONG time_diff, secs, micros;

UWORD beats;

WORD hour;

struct ClockData clock;

t1 = time(NULL);

CurrentTime(&secs,&micros);

time_diff = t1 - secs;

time_norm -= time_diff;

get(app->NU_TimeZone,MUIA_Numeric_Value,&time_zone);

Amiga2Date(time_norm,&clock);

hour = (clock.hour - time_zone) + 1;

if (hour > 23) hour -= 24;
if (hour < 0)  hour += 24;

beatf = (float)((hour*60*60)+(clock.min*60)+clock.sec)/86.4;

beats = beatf;

return(beats);

}


APTR __asm AddAddUIN(REG(a2) APTR pool, REG(a1) struct MSG_AddUIN *adduin)

{

struct MSG_AddUIN *newadduin = NULL;

if (!(newadduin = AllocPooled(pool,sizeof(struct MSG_AddUIN)))) return(NULL);

if (!(newadduin->Nick = AllocPooled(pool,strlen(adduin->Nick)+1))) {
  FreePooled(pool,adduin,sizeof(struct MSG_AddUIN));
  return(NULL);
}
else strcpy(newadduin->Nick,adduin->Nick);

newadduin->UIN = adduin->UIN;

return(newadduin);

}


void __asm RemAddUIN(REG(a2) APTR pool, REG(a1) struct MSG_AddUIN *adduin)

{

FreePooled(pool,adduin->Nick,strlen(adduin->Nick)+1);
FreePooled(pool,adduin,sizeof(struct MSG_AddUIN));

return;

}


LONG __asm CmpAddUIN(REG(a1) struct MSG_AddUIN *a1, REG(a2) struct MSG_AddUIN *a2)

{

if (a1->UIN < a2->UIN) return(-1);
if (a1->UIN > a2->UIN) return(1);

return(0);

}


void __asm DisplayAddUIN(REG(a2) char **array, REG(a1) struct MSG_AddUIN *adduin)

{

static char buf[32], already[5];

if (adduin) {
  sprintf(buf,"%ld",adduin->UIN);
  if (GetContact(adduin->UIN)) strcpy(already,"Yes");
  else strcpy(already,"No");
  *array++ = buf;
  *array++ = adduin->Nick;
  *array   = already;
}
else {
  *array++ = "UIN";
  *array++ = "Nick";
  *array   = "Already have it?";
}

return;

}


void __asm GetAddUINInfo(REG(a2) APTR obj)

{

ULONG entry;

struct MSG_AddUIN *adduin;

get(app->LV_ToAddUIN,MUIA_NList_Active,&entry);

if (entry == MUIV_NList_Active_Off) return;

DoMethod(app->LV_ToAddUIN,MUIM_NList_GetEntry,entry,&adduin);

set(obj,MUIA_UserData,adduin->UIN);

GetUINInfo(obj);

return;

}


void __asm ShareContacts(REG(a2) APTR obj)

{

char msg[450], tmp[50];

int i = 0;

LONG sel = MUIV_NList_NextSelected_Start;

ULONG uin;

struct Contact *user;

get(obj,MUIA_UserData,&uin);

DoMethod(app->LV_OfflineList,MUIM_NList_NextSelected,&sel);

msg[0] = '\0';

while(sel != MUIV_NList_NextSelected_End) {
  DoMethod(app->LV_OfflineList,MUIM_NList_GetEntry,sel,&user);
  sprintf(tmp,"%ld\xFE%s\xFE",user->UIN,GetNick(user->UIN));
  if (strlen(msg) + strlen(tmp) + 4 < 450) {
    i++;
    strcat(msg,tmp);
  }
  DoMethod(app->LV_OfflineList,MUIM_NList_NextSelected,&sel);
}

if (i == 0) return;

sprintf(tmp,"%d\xFE",i);

strins(msg,tmp);

SendAMessage(obj,uin,msg,MSG_ADDUIN,MSG_REMOTE,MSG_VIA_BEST);

return;

}


APTR __asm AddErr(REG(a2) APTR pool, REG(a1) struct ErrorMsgs *err)

{

struct ErrorMsgs *newerr = NULL;

if (!(newerr = AllocPooled(pool,sizeof(struct ErrorMsgs)))) return(NULL);

if (!(newerr->Error = AllocPooled(pool,strlen(err->Error)+1))) {
  FreePooled(pool,err,sizeof(struct ErrorMsgs));
  return(NULL);
}
else strcpy(newerr->Error,err->Error);

newerr->Timehack = err->Timehack;

return(newerr);

}


void __asm RemErr(REG(a2) APTR pool, REG(a1) struct ErrorMsgs *err)

{

FreePooled(pool,err->Error,strlen(err->Error)+1);
FreePooled(pool,err,sizeof(struct ErrorMsgs));

return;

}


LONG __asm CmpErr(REG(a1) struct ErrorMsgs *a1, REG(a2) struct ErrorMsgs *a2)

{

if (a1->Timehack < a2->Timehack) return(-1);
if (a1->Timehack > a2->Timehack) return(1);

return(0);

}


void __asm DisplayErr(REG(a2) char **array, REG(a1) struct ErrorMsgs *err)

{

static char buf[10];

if (err) {
  strncpy(buf,ctime(&err->Timehack)+11,8);
  *array++ = buf;
  *array   = err->Error;
}
else {
  *array++ = "Time";
  *array   = "Error Msg";
}

return;

}


void HandleError(UBYTE type, char *ErrorMsg, ...)

{

BOOL *winopen, *option = NULL, flag = FALSE;

va_list ap;

struct ErrorMsgs Err;

va_start(ap,ErrorMsg);

vsprintf(err_buf,ErrorMsg,ap);

va_end(ap);

if (type != DBG_OTH_FATL && type != DBG_OTH_INFO && type != DBG_UDP_ERRS && type != DBG_TCP_ERRS) {
  if (type == DBG_UDP_PKTS) get(app->CH_UDPPkts,MUIA_Selected,&option);
  if (type == DBG_UDP_DBUG) get(app->CH_UDPDebug,MUIA_Selected,&option);
  if (type == DBG_TCP_PKTS) get(app->CH_TCPPkts,MUIA_Selected,&option);
  if (type == DBG_TCP_DBUG) get(app->CH_TCPDebug,MUIA_Selected,&option);
  if (!option) return;
}
else flag = TRUE;

Err.Timehack = time(NULL);
Err.Error = err_buf;

DoMethod(app->LV_Errors,MUIM_NList_InsertSingle,&Err,MUIV_NList_Insert_Bottom);
DoMethod(app->LV_Errors,MUIM_NList_Jump,MUIV_NList_Jump_Bottom);

if (flag) {
  get(app->WI_ErrorWin,MUIA_Window_Open,&winopen);
  if (!winopen) set(app->WI_ErrorWin,MUIA_Window_Open,TRUE);
}

return;

}


void PrepTCPMessage(struct TCP_Message *tcpmsg, ULONG ToUIN)

{

int i;

UWORD MsgStatus[] = {TCP_MSG_REAL, TCP_MSGF_S_INVISIBLE, TCP_MSGF_S_NA, TCP_MSG_REAL, TCP_MSGF_S_OCCUPIED, TCP_MSGF_S_AWAY, TCP_MSGF_S_DND, TCP_MSG_REAL};

ULONG index, total;

struct Contact *user;
struct Sockets *socks;

get(app->STR_ICQUIN,MUIA_String_Integer,&tcpmsg->UIN);

user = GetContact(ToUIN);

tcpmsg->Message = tcpmsg->Chat_Session = tcpmsg->File_Name = LINE;

tcpmsg->X1 = tcpmsg->Chat_X2 = tcpmsg->File_X3 = 0;
tcpmsg->Chat_RevPort = tcpmsg->File_RevPort = 0;
tcpmsg->Chat_Port = tcpmsg->File_Port = tcpmsg->File_Size = 0;

get(app->LV_SockList,MUIA_NList_Entries,&total);

for(i = 0; i < total; i++) {
  DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
  if (socks) if (socks->Type == SOCK_MESSAGE && socks->Dir == TCP_DIR_LISTEN) break;
}

tcpmsg->TCP_MsgIP = socks->IP;
tcpmsg->TCP_RealIP = socks->IP;
tcpmsg->TCP_MsgPort = socks->Port;

get(app->CY_MyStatus,MUIA_Cycle_Active,&index);

tcpmsg->TCP_Status = TCPCodes[index];

if (tcpmsg->MsgCommand != TCP_MSG_AUTO) {
  MsgStatus[0] = MsgStatus[3] = MsgStatus[7] = tcpmsg->MsgCommand;
  tcpmsg->MsgCommand |= MsgStatus[index];
}

return;

}


LONG SendTCPPacket(ULONG to, UWORD cmd, char *buf, UWORD len, UWORD revlen)

{

LONG ret = -2;

struct Contact *user;
struct Sockets *socks;

if (!(user = GetContact(to))) return(FALSE);

if (!(socks = GetSocketFmContact(user,SOCK_MESSAGE))) {
  if (user->CanTCP != 4) return(FALSE);
  if (!(ret = OpenTCPSocket(user,SOCK_MESSAGE,user->IP,user->Port))) {
    if (!(ret = OpenTCPSocket(user,SOCK_MESSAGE,user->RealIP,user->Port))) return(FALSE);
  }
  socks = GetSocketFmContact(user,SOCK_MESSAGE);
  if (user->Status & STATUSF_HIDEIP) socks->Hidden = TRUE;
}

if (ret == -1) return(ret);

if (!socks->HadInit) SendTCPInit(socks->Socket,user,0);

if (cmd != TCP_ACK) {
  if (user->UWin) {
    set(user->UWin->BB_WaitTCP,MUIA_ShowMe,TRUE);
    set(user->UWin->BB_WaitTCP,MUIA_Busy_Speed,MUIV_Busy_Speed_User);
  }
}

send(socks->Socket,(char *)&revlen,2,0);
send(socks->Socket,buf,len,0);

socks->Timehack = time(NULL);

return(ret);

}


void SendTCPMsgViaUDP(ULONG UIN)

{

int i;

ULONG total, Seq;

struct ICQLog *log;
struct TCP_Message TCPMsg;

get(app->LV_ICQCliLog,MUIA_NList_Entries,&total);

if (!total) return;

for(i = 0; i < total; i++) {
  DoMethod(app->LV_ICQCliLog,MUIM_NList_GetEntry,i,&log);
  if (log) {
    if (log->Cmd == TCP_MESSAGE && log->UIN == UIN && log->Pkt) {
      TCP_ParseMsgPacket(&TCPMsg,log->Pkt,&Seq);
      SendAMessage(NULL,log->UIN,TCPMsg.Message,TCPMsg.Type,MSG_REMOTE,MSG_VIA_UDP);
      HandleError(DBG_TCP_DBUG,"Sending a message via UDP from a TCP packet to %s",GetNick(log->UIN));
      HandleError(DBG_TCP_DBUG,"> %s",TCPMsg.Message);
      FreeVec(log->Pkt);
      log->Pkt = NULL;
      log->UIN = 0;
      log->Len = 0;
      DoMethod(app->LV_ICQCliLog,MUIM_NList_Redraw,i);
    }
  }
}
    
return;

}


void __asm SaveErrors(REG(a2) APTR obj)

{

char save_fl[MAXNAMLEN], line[1024];

char title[] = "Save Error Log:";

int i;

LONG entries;

struct AsyncFile     *savefh;
struct ErrorMsgs     *errs;
struct FileRequester *myasl;
struct Window        *mywin = NULL;

struct TagItem MyASLTags[] = {
  {ASLFR_TitleText,    NULL},
  {ASLFR_Window,       NULL},
  {ASLFR_InitialDrawer,NULL},
  {ASLFR_DoSaveMode,   TRUE},
  {ASLFR_RejectIcons,  TRUE},

  {TAG_DONE,NULL},
};

get(app->LV_Errors,MUIA_NList_Entries,&entries);
get(app->WI_Main,MUIA_Window_Window,&mywin);

MyASLTags[0].ti_Data = (ULONG)title;
MyASLTags[1].ti_Data = (ULONG)mywin;
MyASLTags[2].ti_Data = (ULONG)currentdir;

if (entries < 1) return;

if (!(myasl = MUI_AllocAslRequest(ASL_FileRequest,MyASLTags))) return;

if (!MUI_AslRequest(myasl,NULL)) return;

if (LASTCHAR(myasl->fr_Drawer) != ':' && LASTCHAR(myasl->fr_Drawer) != '/') sprintf(save_fl,"%s/%s",myasl->fr_Drawer,myasl->fr_File);
else sprintf(save_fl,"%s%s",myasl->fr_Drawer,myasl->fr_File);

MUI_FreeAslRequest(myasl);

if (!(savefh = OpenAsync(save_fl,MODE_WRITE,AsyncBuf))) {
  HandleError(DBG_OTH_INFO,"Could not open the save file:  %s",save_fl);
  return;
}

for(i = 0; i < entries; i++) {
  DoMethod(app->LV_Errors,MUIM_NList_GetEntry,i,&errs);
  if (errs) {
    line[0] = '\0';
    sprintf(line,"%.8s  %s\n",ctime(&errs->Timehack)+11,errs->Error);
    WriteLineAsync(savefh,line);
  }
}

CloseAsync(savefh);

return;

}


void SendDelayedTCP(struct Sockets *socks)

{

int i;

ULONG total;

UWORD revlen;

struct ICQLog *log;

HandleError(DBG_TCP_DBUG,"SendDelayedTCP()");

get(app->LV_ICQCliLog,MUIA_NList_Entries,&total);

for(i = 0; i < total; i++) {
  DoMethod(app->LV_ICQCliLog,MUIM_NList_GetEntry,i,&log);
  if (log) {
    if (log->Cmd == TCP_MESSAGE && log->UIN == socks->UIN && log->Pkt) {
      HandleError(DBG_TCP_DBUG,"Sending a TCP packet...");
      revlen = BREV_W(log->Len);
      SendTCPPacket(log->UIN,log->Cmd,log->Pkt,log->Len,revlen);
      FreeVec(log->Pkt);
      log->Pkt = NULL;
      log->UIN = 0;
      log->Len = 0;
      DoMethod(app->LV_ICQCliLog,MUIM_NList_Redraw,i);
    }
  }
}

return;

}


void __asm SetUserVisPrefs(REG(a2) APTR obj)

{

BOOL *tick;

ULONG uin;

struct Contact *user;

get(obj,MUIA_UserData,&uin);

if (!(user = GetContact(uin))) return;

get(obj,MUIA_Selected,&tick);

if (obj == user->UWin->CH_SeeInvis) user->SeeInvis = BOOLP(tick);
if (obj == user->UWin->CH_BeInvis) user->BeInvis = BOOLP(tick);
if (obj == user->UWin->CH_EditEMail) user->EditEMail = BOOLP(tick);

user->Changed = TRUE;

return;

}


void __asm OpenEditIgnore(REG(a2) APTR obj)

{

char uin_str[32];

struct IgnoreUIN *ignore;

DoMethod(app->LV_IgnoreUIN,MUIM_NList_GetEntry,MUIV_NList_GetEntry_Active,&ignore);

if (!ignore) return;

sprintf(uin_str,"%ld",ignore->UIN);

set(app->TX_IgnoreUIN,MUIA_Text_Contents,uin_str);
set(app->TX_IgnoreNick,MUIA_Text_Contents,ignore->Nick);
set(app->NU_IgnoreDays,MUIA_Numeric_Value,(ignore->ExpireDays-ignore->Timehack)/86400);

set(app->BT_IgnoreOK,MUIA_UserData,ignore->UIN);

set(app->WI_EditIgnore,MUIA_Window_Open,TRUE);

return;

}


void __asm SetIgnoreEdits(REG(a2) APTR obj)

{

int i;

ULONG total, uin, days;

struct IgnoreUIN *ignore, Ignore;

get(obj,MUIA_UserData,&uin);

get(app->NU_IgnoreDays,MUIA_Numeric_Value,&days);

get(app->LV_IgnoreUIN,MUIA_NList_Entries,&total);

for(i = 0; i < total; i++) {
  DoMethod(app->LV_IgnoreUIN,MUIM_NList_GetEntry,i,&ignore);
  if (ignore) {
    if (ignore->UIN == uin) {
      if (days == -1) ignore->ExpireDays = 0;
      else ignore->ExpireDays = ignore->Timehack+(days*86400);
      DoMethod(app->LV_IgnoreUIN,MUIM_NList_Redraw,i);
      break;
    }
  }
}

if (i == total) {
  Ignore.UIN = uin;
  strcpy(Ignore.Nick,GetNick(uin));
  Ignore.Timehack = time(NULL);
  Ignore.ExpireDays = Ignore.Timehack+(days*86400);
  DoMethod(app->LV_IgnoreUIN,MUIM_NList_InsertSingle,&Ignore,MUIV_NList_Insert_Sorted);
}

set(app->WI_EditIgnore,MUIA_Window_Open,FALSE);

return;

}


void InfoView(APTR Data, UBYTE InfoType)

{

char uinstr[32], auth[5];

switch(InfoType) {
  case INFO_BASIC: {
    struct S_Basic_Info *Basic = Data;
    sprintf(uinstr,"%ld",Basic->UIN);
    set(app->STR_UserUIN,MUIA_Text_Contents,uinstr);
    set(app->STR_UserUIN,MUIA_UserData,Basic->UIN);
    set(app->STR_UserNick,MUIA_Textinput_Contents,Basic->Nick);
    set(app->STR_UserFirst,MUIA_Textinput_Contents,Basic->First);
    set(app->STR_UserLast,MUIA_Textinput_Contents,Basic->Last);
    set(app->STR_UserEMail,MUIA_Text_Contents,Basic->EMail);
    if (Basic->Authorize) strcpy(auth,"No");
    else strcpy(auth,"Yes");
    set(app->STR_UserAuth,MUIA_Text_Contents,auth);
    set(app->STR_UserAuth,MUIA_UserData,Basic->Authorize);
    break;
  }
  case INFO_EXTENDED: {
    char text[64];
    struct S_Ext_Info *Ext = Data;
    set(app->TX_UserCity,MUIA_Text_Contents,Ext->City);
    if (Ext->Country == 0xffff) strcpy(text,"Unspecified");
    else sprintf(text,"%s",FindCountryName(Ext->Country));
    set(app->TX_UserCountry,MUIA_Text_Contents,text);
    set(app->TX_UserCountry,MUIA_UserData,Ext->Country);
    Ext->Timezone = -(Ext->Timezone/2);
    set(app->NU_UserZone,MUIA_Numeric_Value,Ext->Timezone);
    set(app->NU_UserZone,MUIA_UserData,Ext->Timezone);
    set(app->TX_UserState,MUIA_Text_Contents,Ext->State);
    if (Ext->Age == 0xffff) strcpy(text,"Unspecified");
    else sprintf(text,"%d",Ext->Age);
    set(app->TX_UserAge,MUIA_Text_Contents,text);
    set(app->TX_UserAge,MUIA_UserData,Ext->Age);
    set(app->TX_UserSex,MUIA_Text_Contents,Sex[Ext->Sex]);
    set(app->TX_UserSex,MUIA_UserData,Ext->Sex);
    set(app->TX_UserPhone,MUIA_Text_Contents,Ext->Phone);
    set(app->TX_UserURL,MUIA_Text_Contents,Ext->URL);
    if (strlen(Ext->About)) DoMethod(app->LV_UserAbout,MUIM_NList_InsertWrap,Ext->About,-2,MUIV_NList_Insert_Bottom,WRAPCOL0,ALIGN_LEFT);
    break;
  }
  case INFO_META_HOME:
  case INFO_META_WORK:
  case INFO_META_MORE:
  case INFO_META_ABOUT:
  case INFO_META_INTERESTS:
  case INFO_META_AFFILIATIONS:
  case INFO_META_URLCATEGORY:
    break;
}

set(app->WI_Information,MUIA_Window_Open,TRUE);

return;

}


void InfoRefresh(APTR Data, UBYTE InfoType)

{

char tmp_nick[21];

struct Contact *user = NULL;

switch(InfoType) {
  case INFO_BASIC: {
    struct S_Basic_Info *Basic = Data;
    if (!(user = GetContact(Basic->UIN))) return;
    RefreshUInfo(&user->Nick,Basic->Nick);
    RefreshUInfo(&user->First,Basic->First);
    RefreshUInfo(&user->Last,Basic->Last);
    RefreshUInfo(&user->EMail,Basic->EMail);
    user->Authorize = Basic->Authorize;
    break;
  }
  case INFO_EXTENDED: {
    struct S_Ext_Info *Ext = Data;
    if (!(user = GetContact(Ext->UIN))) return;
    RefreshUInfo(&user->City,Ext->City);
    user->Country = Ext->Country;
    user->TimeZone = -(Ext->Timezone/2);
    RefreshUInfo(&user->State,Ext->State);
    user->Age = Ext->Age;
    user->Sex = Ext->Sex;
    RefreshUInfo(&user->Phone,Ext->Phone);
    RefreshUInfo(&user->HomePage,Ext->URL);
    RefreshUInfo(&user->About,Ext->About);
    break;
  }
  case INFO_META_HOME: {
    struct Meta_Info_Home *Home = Data;
    if (!(user = GetContact(UserInfoReqID[1]))) return;
    RefreshUInfo(&user->Nick,Home->Nick);
    RefreshUInfo(&user->First,Home->First);
    RefreshUInfo(&user->Last,Home->Last);
    RefreshUInfo(&user->EMail,Home->EMail_Primary);
    RefreshUInfo(&user->EMail_Secondary,Home->EMail_Secondary);
    RefreshUInfo(&user->EMail_Old,Home->EMail_Old);
    RefreshUInfo(&user->City,Home->City);
    RefreshUInfo(&user->State,Home->State);
    RefreshUInfo(&user->Phone,Home->Phone);
    RefreshUInfo(&user->FAX,Home->FAX);
    RefreshUInfo(&user->Street,Home->Street);
    RefreshUInfo(&user->Cellular,Home->Cellular);
    RefreshUInfo(&user->ZipCode,Home->ZipCode);
    user->Country = Home->Country;
    HandleError(DBG_UDP_DBUG,"Timezone = %d",Home->Timezone);
    user->TimeZone = -(Home->Timezone/2);
    user->Authorize = Home->Flag1;
    break;
  }
  case INFO_META_WORK: {
    struct Meta_Info_Work *Work = Data;
    if (!(user = GetContact(UserInfoReqID[1]))) return;
    RefreshUInfo(&user->Work_City,Work->City);
    RefreshUInfo(&user->Work_State,Work->State);
    RefreshUInfo(&user->Work_Phone,Work->Phone);
    RefreshUInfo(&user->Work_FAX,Work->FAX);
    RefreshUInfo(&user->Work_Address,Work->Address);
    RefreshUInfo(&user->Work_ZipCode,Work->ZipCode);
    user->Work_Country = Work->Country;
    RefreshUInfo(&user->Work_Company,Work->Company);
    RefreshUInfo(&user->Work_Department,Work->Department);
    RefreshUInfo(&user->Work_Position,Work->Position);
    user->Work_Occupation = Work->Occupation;
    RefreshUInfo(&user->Work_URL,Work->URL);
    break;
  }
  case INFO_META_MORE: {
    struct Meta_Info_More *More = Data;
    if (!(user = GetContact(UserInfoReqID[1]))) return;
    user->Age = More->Age;
    user->Sex = More->Sex;
    RefreshUInfo(&user->HomePage,More->URL);
    HandleError(DBG_UDP_DBUG,"BD_Year = %d",More->BDay_Year);
    HandleError(DBG_UDP_DBUG,"BD_Month = %d",More->BDay_Month);
    HandleError(DBG_UDP_DBUG,"BD_Day = %d",More->BDay_Day);
    user->BDay_Year = More->BDay_Year;
    user->BDay_Month = More->BDay_Month;
    user->BDay_Day = More->BDay_Day;
    if (More->Language1 == 0xFF) user->Language1 = 0x00;
    else user->Language1 = More->Language1;
    if (More->Language2 == 0xFF) user->Language2 = 0x00;
    else user->Language2 = More->Language2;
    if (More->Language3 == 0xFF) user->Language3 = 0x00;
    else user->Language3 = More->Language3;
    break;
  }
  case INFO_META_ABOUT: {
    struct Meta_Info_About *About = Data;
    if (!(user = GetContact(UserInfoReqID[1]))) return;
    RefreshUInfo(&user->About,About->About);
    break;
  }
  case INFO_META_INTERESTS:
  case INFO_META_AFFILIATIONS:
  case INFO_META_URLCATEGORY:
    break;
}

if (user) {
  if (!user->Nick) {
    sprintf(tmp_nick,"%ld",user->UIN);
    RefreshUInfo(&user->Nick,tmp_nick);
  }
  if (user->Status == STATUS_NEWUIN) {
    UWORD len;
    struct C_ContactList CList;
    user->Status = STATUS_OFFLINE;
    Header.Command = C_CONTACT_LIST;
    CList.UIN_Count = 1;
    CList.UIN[0] = user->UIN;
    len = UDP_CreatePacket(&Header,&CList,UDP_Buf);
    send_udp_pkt(UDP_Buf,len,Header.UIN);
    Add2Log(LOG_CLIENT,&Header,FALSE,len,UDP_Buf);
    sprintf(maintitle,"STRICQ (%d)",++contacts_cnt);
    set(app->WI_Main,MUIA_Window_Title,maintitle);
    DoMethod(app->LV_OfflineList,MUIM_NList_Sort);
  }
}

UpdateUserWin(user);

return;

}


BOOL RefreshUInfo(char **old, char *new)

{

char *tmp;

if (!new) {
  if (*old) FreeVec(*old);
  *old = NULL;
  return(TRUE);
}

if (*old) {
  if (!strcmp(*old,new)) return(TRUE);
  HandleError(DBG_UDP_DBUG,"RefreshUInfo() - old = %p, *old = %s, new = %s",old,*old,new);
}

if (strlen(new)) {
  tmp = *old;
  if (!(*old = AllocVec(strlen(new)+1,MEMF_CLEAR))) {
    HandleError(DBG_OTH_INFO,"RefreshUInfo() - Could not allocate %d bytes.",strlen(new)+1);
    *old = tmp;
    return(FALSE);
  }
  else if (tmp) FreeVec(tmp);
  strcpy(*old,new);
}
else {
  if (*old) FreeVec(*old);
  *old = NULL;
}

return(TRUE);

}


void InfoGrabMe(APTR Data, UBYTE InfoType)

{

char text[64];

switch(InfoType) {
  case INFO_BASIC: {
    struct S_Basic_Info *Basic = Data;
    set(app->STR_Nick,MUIA_String_Contents,Basic->Nick);
    set(app->STR_First,MUIA_String_Contents,Basic->First);
    set(app->STR_Last,MUIA_String_Contents,Basic->Last);
    set(app->STR_EMail,MUIA_String_Contents,Basic->EMail);
    Basic->Authorize = -Basic->Authorize + 1;
    set(app->RD_ReqAuth,MUIA_Radio_Active,Basic->Authorize);
    break;
  }
  case INFO_EXTENDED: {
    struct S_Ext_Info *Ext = Data;
    set(app->STR_City,MUIA_String_Contents,Ext->City);
    sprintf(text,"%d %s",Ext->Country,FindCountryName(Ext->Country));
    set(app->STR_Country,MUIA_String_Contents,text);
    set(app->STR_Country,MUIA_UserData,Ext->Country);
    Ext->Timezone = -(Ext->Timezone / 2);
    set(app->NU_TimeZone,MUIA_Numeric_Value,Ext->Timezone);
    set(app->STR_State,MUIA_String_Contents,Ext->State);
    set(app->STR_Age,MUIA_String_Integer,Ext->Age);
    set(app->CY_Sex,MUIA_Cycle_Active,Ext->Sex);
    set(app->STR_Phone,MUIA_String_Contents,Ext->Phone);
    set(app->STR_Page,MUIA_String_Contents,Ext->URL);
    set(app->TI_About,MUIA_Textinput_Contents,Ext->About);
    break;
  }
  case INFO_META_HOME: {
    struct Meta_Info_Home *Home = Data;
    set(app->STR_Nick,MUIA_String_Contents,Home->Nick);
    set(app->STR_First,MUIA_String_Contents,Home->First);
    set(app->STR_Last,MUIA_String_Contents,Home->Last);
    set(app->STR_EMail,MUIA_String_Contents,Home->EMail_Primary);
    set(app->STR_EMail2,MUIA_String_Contents,Home->EMail_Secondary);
    set(app->STR_EMailOld,MUIA_String_Contents,Home->EMail_Old);
    set(app->STR_City,MUIA_String_Contents,Home->City);
    set(app->STR_State,MUIA_String_Contents,Home->State);
    set(app->STR_Phone,MUIA_String_Contents,Home->Phone);
    set(app->STR_FAX,MUIA_String_Contents,Home->FAX);
    set(app->TI_StreetAd,MUIA_Textinput_Contents,Home->Street);
    set(app->STR_Cellular,MUIA_String_Contents,Home->Cellular);
    set(app->STR_ZipCode,MUIA_String_Contents,Home->ZipCode);
    sprintf(text,"%d %s",Home->Country,FindCountryName(Home->Country));
    set(app->STR_Country,MUIA_String_Contents,text);
    set(app->STR_Country,MUIA_UserData,Home->Country);
    Home->Timezone = -(Home->Timezone / 2);
    set(app->NU_TimeZone,MUIA_Numeric_Value,Home->Timezone);
    Home->Flag1 = -Home->Flag1 + 1;
    set(app->RD_ReqAuth,MUIA_Radio_Active,Home->Flag1);
    break;
  }
  case INFO_META_WORK: {
    struct Meta_Info_Work *Work = Data;
    set(app->STR_WkCity,MUIA_String_Contents,Work->City);
    set(app->STR_WkState,MUIA_String_Contents,Work->State);
    set(app->STR_WkPhone,MUIA_String_Contents,Work->Phone);
    set(app->STR_WkFAX,MUIA_String_Contents,Work->FAX);
    set(app->TI_WorkAd,MUIA_Textinput_Contents,Work->Address);
    set(app->STR_WkZipCode,MUIA_String_Contents,Work->ZipCode);
    sprintf(text,"%d %s",Work->Country,FindCountryName(Work->Country));
    set(app->STR_WkCountry,MUIA_String_Contents,text);
    set(app->STR_WkCountry,MUIA_UserData,Work->Country);
    set(app->STR_CoName,MUIA_String_Contents,Work->Company);
    set(app->STR_DivDept,MUIA_String_Contents,Work->Department);
    set(app->STR_Position,MUIA_String_Contents,Work->Position);
    set(app->CY_Occupation,MUIA_Cycle_Active,Work->Occupation);
    set(app->STR_WkURL,MUIA_String_Contents,Work->URL);
    break;
  }
  case INFO_META_MORE: {
    struct Meta_Info_More *More = Data;
    set(app->STR_Age,MUIA_String_Integer,More->Age);
    set(app->CY_Sex,MUIA_Cycle_Active,More->Sex);
    set(app->STR_Page,MUIA_String_Contents,More->URL);
    set(app->NU_BDYear,MUIA_Numeric_Value,More->BDay_Year);
    set(app->CY_BDMonth,MUIA_Cycle_Active,More->BDay_Month-1);
    set(app->STR_BDDay,MUIA_String_Integer,More->BDay_Day);
    if (More->Language1 == 0xFF) More->Language1 = 0x00;
    set(app->CY_Lang1,MUIA_Cycle_Active,More->Language1);
    if (More->Language2 == 0xFF) More->Language2 = 0x00;
    set(app->CY_Lang2,MUIA_Cycle_Active,More->Language2);
    if (More->Language3 == 0xFF) More->Language3 = 0x00;
    set(app->CY_Lang3,MUIA_Cycle_Active,More->Language3);
    break;
  }
  case INFO_META_ABOUT: {
    struct Meta_Info_About *About = Data;
    set(app->TI_About,MUIA_Textinput_Contents,About->About);
    break;
  }
  case INFO_META_INTERESTS:
  case INFO_META_AFFILIATIONS:
  case INFO_META_URLCATEGORY:
    break;
}

return;

}


void ChangeZodiacPic(struct Contact *user, BOOL ForOwner)

{

static char *Zodiacs[] = {"", "Capricorn", "Aquarius", "Pisces", "Aries", "Tarus", "Gemini",
                          "Cancer", "Leo", "Virgo", "Libra", "Scorpio", "Sagittarus", NULL};

APTR NewImgObj, GPObj, DTObj;

char zodiac_fl[MAXNAMLEN];

int index;

ULONG month, day;

if (ForOwner) {
  get(app->CY_BDMonth,MUIA_Cycle_Active,&month);
  get(app->STR_BDDay,MUIA_String_Integer,&day);
  GPObj = app->GP_DTGroup;
  DTObj = app->DT_Zodiac;
}
else {
  if (!user) return;
  if (!user->UWin) return;
  month = user->BDay_Month;
  day = user->BDay_Day;
  GPObj = user->UWin->GP_DTGroup;
  DTObj = user->UWin->DT_Zodiac;
}

switch(month) {
  case 0:
    index = 0;
    break;
  case 1:
    index = 1;
    if (day > 20) index = 2;
    break;
  case 2:
    index = 2;
    if (day > 18) index = 3;
    break;
  case 3:
    index = 3;
    if (day > 20) index = 4;
    break;
  case 4:
    index = 4;
    if (day > 20) index = 5;
    break;
  case 5:
    index = 5;
    if (day > 21) index = 6;
    break;
  case 6:
    index = 6;
    if (day > 21) index = 7;
    break;
  case 7:
    index = 7;
    if (day > 22) index = 8;
    break;
  case 8:
    index = 8;
    if (day > 23) index = 9;
    break;
  case 9:
    index = 9;
    if (day > 23) index = 10;
    break;
  case 10:
    index = 10;
    if (day > 23) index = 11;
    break;
  case 11:
    index = 11;
    if (day > 22) index = 12;
    break;
  case 12:
    index = 12;
    if (day > 21) index = 1;
    break;
}

sprintf(zodiac_fl,"%sImages/%s",currentdir,Zodiacs[index]);

if (!(NewImgObj = DatatypeObject, MUIA_Dtpic_Name, zodiac_fl, End)) {
  HandleError(DBG_OTH_INFO,"Error creating a new Zodiac Image");
  return;
}

DoMethod(GPObj,MUIM_Group_InitChange);

if (DTObj) {
  DoMethod(GPObj,OM_REMMEMBER,DTObj);
  MUI_DisposeObject(DTObj);
}

DTObj = NewImgObj;

DoMethod(GPObj,OM_ADDMEMBER,DTObj);

DoMethod(GPObj,MUIM_Group_ExitChange);

if (ForOwner) app->DT_Zodiac = DTObj;
else user->UWin->DT_Zodiac = DTObj;

return;

}


void __asm ChangeZodiac(REG(a2) APTR obj)

{

if (obj == app->CY_BDMonth) ChangeZodiacPic(NULL,TRUE);

return;

}


void __asm ResetSockets(REG(a2) APTR obj)

{

int i;

ULONG total;

struct Sockets *socks;

//HandleError(DBG_TCP_DBUG,"ResetSockets()");

if (Online) return;

get(app->LV_SockList,MUIA_NList_Entries,&total);

if (total) {
  for(i = total-1; i>-1; i--) {
    DoMethod(app->LV_SockList,MUIM_NList_GetEntry,i,&socks);
    if (socks) DelSockets(socks->Socket);
  }
}

CloseLibrary(SocketBase);

if (!(SocketBase = OpenLibrary("bsdsocket.library",3))) fail(NULL,"bsdsocket.library is no longer present!");
else HandleError(DBG_TCP_DBUG,"ResetSockets() - Success!");

return;

}
