dslinux/user/bitchx/dll/aim/toc BUGS Makefile.in PROTOCOL README TODO buddy.c interface.c ll.c ll.h misc.c network.c out proxy.h server.c toc.c toc.h util.c

stsp stsp at user.in-berlin.de
Sun Jul 2 15:18:33 CEST 2006


Update of /cvsroot/dslinux/dslinux/user/bitchx/dll/aim/toc
In directory antilope:/tmp/cvs-serv9280/dll/aim/toc

Added Files:
	BUGS Makefile.in PROTOCOL README TODO buddy.c interface.c ll.c 
	ll.h misc.c network.c out proxy.h server.c toc.c toc.h util.c 
Log Message:
Adding pristine copy of BitchX so I can branch from it.


--- NEW FILE: PROTOCOL ---
# Copyright (c) 1998-9 America Online, Inc. All Rights Reserved.
#
#   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.

Version: TOC1.0

This document describes the protocol between TOC and TOC clients.
The protocol is built on TCP.  Framing is done by SFLAP,
described at the bottom of this document.  Inside each
SFLAP frame is a TOC command.

The TOC protocol is ASCII based, and special attention
must be placed argument separation.  The separator and 
the rules of separation are different for messages inbound 
to TOC and outbound to the client.  The rules of separation
are described in sections below.

The TOC server is built mainly to service the TIC and TiK clients.  Since
the TIC client is a Java applet, and downloadable, TOC will NOT support
multiple TOC protocol versions at the same time.   Therefore, TiK
users will be forced to upgrade if the protocol version changes.  
TOC sends down the protocol version it expects the client
to speak and understand.  Note, the protocol version is a string.

Important Notes
===============
* TOC will drop the connection if a command exceeds the maximum
  length, which is currently 2048 bytes.  So the client needs to 
  spend special attention to im, chat, and config message lengths.
  There is an 8k length maximum from TOC to the client.

* No commands should be sent to TOC (besides toc_signon) before 
  a SIGN_ON is received.  If you do send a command before SIGN_ON
  the command will be ignored, and in some case the connection
  will be dropped.

* Initial permit/deny items should be sent after receiving SIGN_ON 
  but before sending toc_init_done, otherwise the user will flash
  on peoples buddylist who the user has denied.  You will probably
  want to send the toc_add_buddies at this time also.

* After TOC sends the PAUSE message to a client, all messages sent 
  to TOC will be ignored, and in some cases the connection will 
  be dropped.  Another SIGN_ON message will be sent to the client 
  when it is online again.  The buddy list and permit/deny items must 
  be sent again, followed by the toc_init_done.  In most cases the 
  SIGN_ON message will be sent between 1-2 seconds after the 
  PAUSE message.  Therefore a client could choose to ignore the 
  PAUSE message and hope nothing bad happens.


Client -> TOC
==============
The commands and the arguments are usually separated by whitespaces.  Arguments
with whitespace characters should be enclosed in quotes.  Dollar signs, 
curly brackets, square brackets, parentheses, quotes, and backslashes 
must all be backslashed whether in quotes or not.  It is usually 
a good idea just to use quotes no matter what.  All user names from clients 
to TOC should be normalized (spaces removed and lowercased), and therefore
are the one exception to the always use quotes rule.

When sending commands to the server you will not get a response
back confirming that the command format was correct or not!  However
in some cases if the command format was incorrect the connection
will be dropped.


RoastingString="Tic/Toc"

toc_signon <authorizer host> <authorizer port> <User Name> <Password> 
           <language> <version>
    The password needs to be roasted with the Roasting String if
    coming over a FLAP connection, CP connections don't use
    roasted passwords.  The language specified will be used
    when generating web pages, such as the get info pages.
    Currently the only supported language is "english".
    If the language sent isn't found, the default "english"
    language will be used.  The version string will be used
    for the client identity, and must be less then 50
    characters.

    Passwords are roasted when sent to the host.  This is done so they 
    aren't sent in "clear text" over the wire, although they are still 
    trivial to decode.  Roasting is performed by first xoring each byte 
    in the password with the equivalent modulo byte in the roasting 
    string.  The result is then converted to ascii hex, and prepended 
    with "0x".  So for example the password "password" roasts to 
    "0x2408105c23001130"

toc_init_done
    Tells TOC that we are ready to go online.  TOC clients should first 
    send TOC the buddy list and any permit/deny lists.  However toc_init_done
    must be called within 30 seconds after toc_signon, or the connection
    will be dropped.  Remember, it can't be called until after the SIGN_ON
    message is received.  Calling this before or multiple times after a
    SIGN_ON will cause the connection to be dropped.

toc_send_im <Destination User> <Message> [auto]
    Send a message to a remote user.  Remember to quote and encode the 
    message.  If the optional string "auto" is the last argument, then the 
    auto response flag will be turned on for the im. 

toc_add_buddy <Buddy User 1> [<Buddy User2> [<Buddy User 3> [...]]]
    Add buddies to your buddy list.  This does not change your
    saved config.

toc_remove_buddy <Buddy User 1> [<Buddy User2> [<Buddy User 3> [...]]]
    Remove buddies from your buddy list.  This does not change your
    saved config.

toc_set_config <Config Info>
    Set the config information for this user.  The config information
    is line oriented with the first character being the item type,
    followed by a space, with the rest of the line being the item
    value.  Only letters, numbers, and spaces should be used.  Remember
    you will have to enclose the entire config in quotes.

    Item Types:
    g - Buddy Group (All Buddies until the next g or the end of config 
		     are in this group.)
    b - A Buddy 
    p - Person on permit list
    d - Person on deny list
    m - Permit/Deny Mode.  Possible values are
	1 - Permit All
	2 - Deny All
	3 - Permit Some
	4 - Deny Some

toc_evil <User> <norm|anon>
    Evil/Warn someone else.  The 2nd argument is either the string
    "norm" for a normal warning, or "anon" for an anonymous 
    warning.  You can only evil people who have recently sent you
    ims.  The higher someones evil level, the slower they can
    send message.

toc_add_permit [ <User 1> [<User 2> [...]]]
    ADD the following people to your permit mode.  If
    you are in deny mode it will switch you to permit
    mode first.  With no arguments and in deny mode
    this will switch you to permit none. If already
    in permit mode, no arguments does nothing
    and your permit list remains the same.

toc_add_deny [ <User 1> [<User 2> [... ]]]
    ADD the following people to your deny mode. If
    you are in permit mode it will switch you to
    deny mode first.  With no arguments and in permit
    mode, this will switch you to deny none. If
    already in deny mode, no arguments does nothing
    and your deny list remains unchanged.

toc_chat_join <Exchange> <Chat Room Name>
    Join a chat room in the given exchange.  Exchange is
    an integer that represents a group of chat rooms.
    Different exchanges have different properties.  For
    example some exchanges might have room replication (ie
    a room never fills up, there are just multiple
    instances.) and some exchanges might have navigational
    information, and some exchanges might have ...  Currently
    exchange should always be 4, however this may
    change in the future.  You will either
    receive an ERROR if the room couldn't be joined
    or a CHAT_JOIN message.  The Chat Room Name
    is case insensitive and consecutive spaces
    are removed.

toc_chat_send <Chat Room ID> <Message>
    Send a message in a chat room using the chat room
    id from CHAT_JOIN.  Since reflection is always on in
    TOC, you do not need to add the message to your chat UI,
    since you will get a CHAT_IN with the message.  
    Remember to quote and encode the message.

toc_chat_whisper <Chat Room ID> <dst_user> <Message>
    Send a message in a chat room using the chat room
    id from CHAT_JOIN.  This message is directed at
    only one person.  (Currently you DO need to add this to
    your UI.)  Remember to quote and encode the message.  
    Chat whispering is different from IMs since it is linked
    to a chat room, and should usually be displayed in the chat
    room UI.

toc_chat_evil <Chat Room ID> <User> <norm|anon>
    Evil/Warn someone else inside a chat room.  The 3rd argument is either 
    the string "norm" for a normal warning, or "anon" for an anonymous 
    warning.  Currently chat evil is not turned on in the chat complex.

toc_chat_invite <Chat Room ID> <Invite Msg> <buddy1> [<buddy2> [<buddy3> [...]]]
    Once you are inside a chat room you can invite other people into
    that room.  Remember to quote and encode the invite message.

toc_chat_leave <Chat Room ID>
    Leave the chat room.

toc_chat_accept <Chat Room ID>
    Accept a CHAT_INVITE message from TOC.  The server will send a
    CHAT_JOIN in response.

toc_get_info <username>
    Gets a user's info a GOTO_URL or ERROR message will be sent back to the 
    client.

toc_set_info <info information>
    Set the LOCATE user information.  This is basic HTML.
    Remember to encode the info.

toc_set_away [<away message>]
    if the away message is present, then the unavailable
    status flag is set for the user.  If the away message
    is not present, then the unavailable status flag is
    unset.  The away message is basic HTML, remember to
    encode the information.

toc_get_dir <username>
    Gets a user's dir info a GOTO_URL or ERROR message will be sent back to the 
    client.

toc_set_dir <info information>
    Set the DIR user information.  This is a colon separated fields as in:
    "first name":"middle name":"last name":"maiden name":"city":"state":"country":"email":"allow web searches"
    Should return a DIR_STATUS msg.  Having anything in the "allow web searches"
    field allows people to use web-searches to find your directory info.
    Otherwise, they'd have to use the client.  

toc_dir_search <info information>
    Perform a search of the Oscar Directory, using colon separated fields as in:
    "first name":"middle name":"last name":"maiden name":"city":"state":"country":"email"
    Returns either a GOTO_URL or ERROR msg.  

toc_set_idle <idle secs>
    Set idle information. If <idle secs> is 0 then the user isn't idle at all.
    If <idle secs> is greater then 0 then the user has already been idle
    for <idle secs> number of seconds.  The server will automatically
    keep incrementing this number, so do not repeatedly call with new
    idle times.


TOC -> Client
==============
All user names from TOC to client are NOT normalized, and are
sent as they should be displayed.  String are NOT encoded, instead
we use colons as separators.  So that you can have colons inside
of messages, everything after the colon before :<Message> should
be considered part of the message (ie don't just "split" on colons,
instead split with a max number of results.)


SIGN_ON:<Client Version Supported>
   This is sent after a successful toc_signon command is sent to TOC.
   If the command was unsuccessful either the FLAP connection will
   be dropped or you will receive a ERROR message.

CONFIG:<config>
   A user's config. Config can be empty in which case the host was not able to
   retrieve it, or a config didn't exist for the user.  See toc_set_config
   above for the format.

NICK:<Nickname>
   Tells you your correct nickname (ie how it should be capitalized and
   spacing)

IM_IN:<Source User>:<Auto Response T/F?>:<Message>
   Receive an IM from some one.  Everything after the third colon is
   the incoming message, including other colons.

UPDATE_BUDDY:<Buddy User>:<Online? T/F>:<Evil Amount>:<Signon Time>:<IdleTime>:<UC>
   This one command handles arrival/depart/updates.  Evil Amount is
   a percentage, Signon Time is UNIX epoc, idle time is in minutes, UC (User Class)
   is a two/three character string.
   uc[0]:
   ' '  - Ignore
   'A'  - On AOL
   uc[1]
   ' '  - Ignore
   'A'  - Oscar Admin
   'U'  - Oscar Unconfirmed
   'O'  - Oscar Normal
   uc[2] 
   '\0' - Ignore
   ' '  - Ignore
   'U'  - The user has set their unavailable flag.



ERROR:<Error Code>:Var args
   * General Errors *
   901   - $1 not currently available
   902   - Warning of $1 not currently available
   903   - A message has been dropped, you are exceeding
	   the server speed limit
   * Chat Errors  *
   950   - Chat in $1 is unavailable.

   * IM & Info Errors *
   960   - You are sending message too fast to $1
   961   - You missed an im from $1 because it was too big.
   962   - You missed an im from $1 because it was sent too fast.

   * Dir Errors *
   970   - Failure
   971   - Too many matches
   972   - Need more qualifiers
   973   - Dir service temporarily unavailable
   974   - Email lookup restricted
   975   - Keyword Ignored
   976   - No Keywords
   977   - Language not supported
   978   - Country not supported
   979   - Failure unknown $1

   * Auth errors *
   980   - Incorrect nickname or password.
   981   - The service is temporarily unavailable.
   982   - Your warning level is currently too high to sign on.
   983   - You have been connecting and
	   disconnecting too frequently.  Wait 10 minutes and try again.
	   If you continue to try, you will need to wait even longer.
   989   - An unknown signon error has occurred $1


EVILED:<new evil>:<name of eviler, blank if anonymous>
   The user was just eviled.

CHAT_JOIN:<Chat Room Id>:<Chat Room Name>
   We were able to join this chat room.  The Chat Room Id is
   internal to TOC.

CHAT_IN:<Chat Room Id>:<Source User>:<Whisper? T/F>:<Message>
   A chat message was sent in a chat room.

CHAT_UPDATE_BUDDY:<Chat Room Id>:<Inside? T/F>:<User 1>:<User 2>...
   This one command handles arrival/departs from a chat room.  The
   very first message of this type for each chat room contains the
   users already in the room.

CHAT_INVITE:<Chat Room Name>:<Chat Room Id>:<Invite Sender>:<Message>
   We are being invited to a chat room.

CHAT_LEFT:<Chat Room Id>
   Tells tic connection to chat room has been dropped

GOTO_URL:<Window Name>:<Url>
   Goto a URL.  Window Name is the suggested internal name of the window
   to use.  (Java supports this.) 

DIR_STATUS:<Return Code>
   

PAUSE
   Tells TIC to pause so we can do migration

Typical Signon Process
======================
Except for the section marked optional this is an sequential
process.  Each line MUST occur before the following line.

* Client connects to TOC
* Client sends "FLAPON\r\n\r\n"
* TOC sends Client FLAP SIGNON
* Client sends TOC FLAP SIGNON
* Client sends TOC "toc_signon" message
* if login fails TOC drops client's connection
  else TOC sends client SIGN_ON reply
* if Client doesn't support version it drops the connection

[BEGIN OPTIONAL]
    * TOC sends Client CONFIG
    * Client sends TOC permit/deny stuff
    * Client sends TOC toc_add_buddy message
[END OPTIONAL]

* Client sends TOC toc_init_done message


SFLAP Documentation
===================
SFLAP is pretty much a FLAP connection except the DATA frame payload is a null
terminated string when traveling from client to host, it is NOT null
terminated when traveling from host to client.  The FLAP Header is binary 
data, and is in network byte order.  The data portion is at offset 6, after the
header.  The sequence number is sequential in each direction.  So
packets from the server to client have one sequence number, while
the packets from the client to server have an independent
increasing number.

FLAP Header (6 bytes)
-----------
Offset   Size  Type
0        1     ASTERISK (literal ASCII '*')
1        1     Frame Type
2        2     Sequence Number
4        2     Data Length


Valid Frame Type Values
-----------------------
1   SIGNON
2   DATA
3   ERROR     (Not used by TOC)
4   SIGNOFF   (Not used by TOC)
5   KEEP_ALIVE


TOC SIGNON FRAME TYPE
---------------------
Sequence Number contains the initial sequence number used in each direction.
Data Length contains the payload length, with the payload described
below.  The payload area is NOT null terminated.

Host To Client:
    4 byte FLAP version (1)

Client To Host:  
    4 byte FLAP version (1)
    2 byte TLV Tag (1)
    2 byte Normalized User Name Length
    N byte Normalized User Name  (NOT null terminated)

    
TOC DATA FRAME TYPE
-------------------
Sequence Number contains the next sequence number.
Data Length is the length of the payload, including the null termination
from client to host.


--- NEW FILE: ll.c ---
/* 
 * Simple linked list library (replaces GList stuff)
 * Yea, it isnt efficient, but its only meant to be used for buddy lists (n < 100) THAT AINT LARGE :)
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ll.h"

/* Creation */

LL CreateLL() {
	LL newlist;
	LLE head;
	newlist = (LL) malloc(sizeof(struct _ll));
	head = (LLE) CreateLLE("head element",NULL,NULL);
	if ( ! head )
		return NULL;
	newlist->head = head;
	newlist->items = 0;
	newlist->curr = head;
	newlist->free_e = NULL;
	return newlist;
}

LLE CreateLLE (char *key, void *data, LLE next) {
	LLE newe;
	newe = (LLE) malloc(sizeof(struct _lle)); 
	if ( ! newe ) {
		perror("MEM allocation errory!");
		return NULL;
	}
	newe->key = (char *) malloc(strlen(key)+1);
	strcpy(newe->key,key);
	newe->data = data;
	newe->next = next;
	return newe;
}

void SetFreeLLE(LL List, void (*free_e)(void *)) {
	List->free_e = free_e;
}

int AddToLL(LL List, char *key, void *data) {
	LLE p = List->head;
	LLE e;
	while ( p->next != NULL ) {
		p = p->next;
	}
	e = CreateLLE(key,data,NULL);
	p->next = e;
	List->items++;
	return 1;
}

LLE FindInLL(LL List, char *key) {
	LLE p = List->head->next;	
	while ( p != NULL ) {
	/*	debug_printf("p != null, key = '%s'",p->key); */
		if ( ! strcasecmp(p->key,key) ) 
			break;
		p = p->next;
	}	
	return p;	
}

void *GetDataFromLLE(LLE e) {
	if ( e == NULL ) 
		return NULL;
	else 
		return e->data;
}

/* Removing Items from List */

int RemoveFromLL(LL List, LLE e) {
	LLE p = List->head;
	LLE b = NULL;
	while ( p != NULL && p != e ) {
		b = p;
		p = p->next;
	}	
	if ( p == NULL ) 
		return -1;
	b->next = p->next;
	FreeLLE(p, List->free_e);	
	List->items--;
	return 1;
}

int RemoveFromLLByKey(LL List, char *key) {
	LLE b = List->head;
	LLE p = b->next;	
	while ( p != NULL ) {
		if ( ! strcasecmp(p->key,key) ) 
			break;
		b = p;	
		p = p->next;
	}	
	if ( p == NULL ) 
		return -1;
	b->next = p->next;
	FreeLLE(p, List->free_e);	
	List->items--;
	return 1;
}

/* For easy loop traversals */

LLE GetNextLLE(LL List) {
	if ( List->curr != NULL ) 
		List->curr = List->curr->next;
	return List->curr;
}

void ResetLLPosition(LL List) {
	List->curr = List->head;
}

/* Only Free the keys at the moment */

void FreeLLE(LLE e, void (*free_e)(void *)) {
	if ( e->key != NULL )
		free(e->key);
	if ( free_e != NULL && e->data != NULL) 
		free_e(e->data); 
	free(e);
	return;
}

void FreeLL(LL List) {
	LLE e; 
	LLE n;
	if ( List == NULL ) {
		perror("SERIOUS ERROR: tried to free null list!");
		return;
	}	
	e = List->head->next;
	free(List->head);
	while ( e != NULL ) {
		n = e->next;
		FreeLLE(e, List->free_e);
		e = n;
	}
	free(List);  
	return;
}

--- NEW FILE: toc.c ---
/*
 * gaim
 *
 * Copyright (C) 1998-1999, Mark Spencer <markster at marko.net>
 *
 * 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
 * 
 */


/* 
 * Heavily modified by Nadeem Riaz (nads at bleh.org)
 * for use in libtoc
 */

#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/socket.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "toc.h"

/* descriptor for talking to TOC */
static int toc_fd;
static int seqno;
static unsigned int peer_ver=0;
int state;
/* static int inpa=-1; */
int permdeny = PERMIT_PERMITALL;

int toc_login(char *username, char *password)
{
	char *config;
	struct in_addr *sin;
	char buf[80];
	char buf2[2048];
	
	toc_debug_printf("looking up host! %s", aim_host);

	sin = (struct in_addr *)get_address(aim_host);
	if (!sin) {  
		set_state(STATE_OFFLINE); 
		toc_msg_printf(TOC_CONNECT_MSGS,"Unable to lookup %s", aim_host);
		return -1;
	}
	
	snprintf(toc_addy, sizeof(toc_addy), "%s", inet_ntoa(*sin));
	snprintf(buf, sizeof(buf), "Connecting to %s", inet_ntoa(*sin));
	
	toc_msg_printf(TOC_CONNECT_MSGS,"%s",buf); 
	
	toc_fd = connect_address(sin->s_addr, aim_port);

        if (toc_fd < 0) {
                set_state(STATE_OFFLINE); 
		toc_msg_printf(TOC_CONNECT_MSGS,"Connect to %s failed", inet_ntoa(*sin));
		return -1;
        }

        free(sin);
	
	toc_msg_printf(TOC_CONNECT_MSGS,"Signon: %s",username);
	
	if (toc_signon(username, password) < 0) {
                set_state(STATE_OFFLINE);
		toc_msg_printf(TOC_CONNECT_MSGS,"Disconnected.");
		return -1;
	}

	toc_msg_printf(TOC_CONNECT_MSGS,"Waiting for reply...");
	if (toc_wait_signon() < 0) {
                set_state(STATE_OFFLINE);
		toc_msg_printf(TOC_CONNECT_MSGS,"Authentication Failed");
		return -1;
	}


	snprintf(aim_username, sizeof(aim_username), "%s", username);
	snprintf(aim_password, sizeof(aim_password), "%s", password);

	save_prefs();

	toc_msg_printf(TOC_CONNECT_MSGS,"Retrieving config...");
        if ((config=toc_wait_config()) == NULL) {
		toc_msg_printf(TOC_CONNECT_MSGS,"No Configuration\n");
		set_state(STATE_OFFLINE);
		return -1;

	}
	
	init_lists();
/*        gtk_widget_hide(mainwindow);
	show_buddy_list();  */
        parse_toc_buddy_list(config);
/*        refresh_buddy_window(); */
   
	snprintf(buf2, sizeof(buf2), "toc_init_done");
	sflap_send(buf2, -1, TYPE_DATA);
        
        serv_finish_login();
	return 0;
}

void toc_close()
{
        seqno = 0;
        state = STATE_OFFLINE;
	toc_remove_input_stream(toc_fd);
	close(toc_fd);
	toc_fd=-1;
}

int toc_signon(char *username, char *password)
{
	char buf[BUF_LONG];
	int res;
	struct signon so;

    	toc_debug_printf("State = %d\n", state);

	strncpy(aim_username, username, sizeof(aim_username));
	
	if ((res = write(toc_fd, FLAPON, strlen(FLAPON))) < 0)
		return res;
	/* Wait for signon packet */

	state = STATE_FLAPON;

	if ((res = wait_reply(buf, sizeof(buf)) < 0))
		return res;
	
	if (state != STATE_SIGNON_REQUEST) {
			toc_debug_printf( "State should be %d, but is %d instead\n", STATE_SIGNON_REQUEST, state);
			return -1;
	}
	
	/* Compose a response */
	
	snprintf(so.username, sizeof(so.username), "%s", username);
	so.ver = ntohl(1);
	so.tag = ntohs(1);
	so.namelen = htons(strlen(so.username));	
	
	sflap_send((char *)&so, ntohs(so.namelen) + 8, TYPE_SIGNON);
	
	snprintf(buf, sizeof(buf), 
		"toc_signon %s %d %s %s %s \"%s\"",
		login_host, login_port, normalize(username), roast_password(password), LANGUAGE, REVISION);

        toc_debug_printf("Send: %s\n", buf);

	return sflap_send(buf, -1, TYPE_DATA);
}

int toc_wait_signon()
{
	/* Wait for the SIGNON to be approved */
	char buf[BUF_LEN];
	int res;
	res = wait_reply(buf, sizeof(buf));
	if (res < 0)
		return res;
	if (state != STATE_SIGNON_ACK) {
			toc_debug_printf("State should be %d, but is %d instead\n",STATE_SIGNON_ACK, state);
		return -1;
	}
	return 0;
}


int wait_reply(char *buffer, int buflen)
{
        int res=6;
	struct sflap_hdr *hdr=(struct sflap_hdr *)buffer;
        char *c;

        while((res = read(toc_fd, buffer, 1))) {
		if (res < 0)
			return res;
		if (buffer[0] == '*')
                        break;

	}

	res = read(toc_fd, buffer+1, sizeof(struct sflap_hdr) - 1);

        if (res < 0)
		return res;

	res += 1;
	
        
	toc_debug_printf( "Rcv: %s %s\n",print_header(buffer), "");
	
        while (res < (sizeof(struct sflap_hdr) + ntohs(hdr->len))) {
		res += read(toc_fd, buffer + res, (ntohs(hdr->len) + sizeof(struct sflap_hdr)) - res);
		/* while(gtk_events_pending())
			gtk_main_iteration(); */
	}
        
        if (res >= sizeof(struct sflap_hdr)) 
		buffer[res]='\0';
	else
		return res - sizeof(struct sflap_hdr);
		
	switch(hdr->type) {
	case TYPE_SIGNON:
		memcpy(&peer_ver, buffer + sizeof(struct sflap_hdr), 4);
		peer_ver = ntohl(peer_ver);
		seqno = ntohs(hdr->seqno);
		state = STATE_SIGNON_REQUEST;
		break;
	case TYPE_DATA:
		if (!strncasecmp(buffer + sizeof(struct sflap_hdr), "SIGN_ON:", strlen("SIGN_ON:")))
			state = STATE_SIGNON_ACK;
		else if (!strncasecmp(buffer + sizeof(struct sflap_hdr), "CONFIG:", strlen("CONFIG:"))) {
			state = STATE_CONFIG;
		} else if (state != STATE_ONLINE && !strncasecmp(buffer + sizeof(struct sflap_hdr), "ERROR:", strlen("ERROR:"))) {
			c = strtok(buffer + sizeof(struct sflap_hdr) + strlen("ERROR:"), ":");
			translate_toc_error_code(c);
			toc_debug_printf("ERROR CODE: %s\n",c);
		}

		toc_debug_printf("Data: %s\n",buffer + sizeof(struct sflap_hdr));

		break;
	default:
			toc_debug_printf("Unknown/unimplemented packet type %d\n",hdr->type);
	}
        return res;
}

int sflap_send(char *buf, int olen, int type)
{
	int len;
	int slen=0;
	struct sflap_hdr hdr;
	char obuf[MSG_LEN];

        /* One _last_ 2048 check here!  This shouldn't ever
         * get hit though, hopefully.  If it gets hit on an IM
         * It'll lose the last " and the message won't go through,
         * but this'll stop a segfault. */
        if (strlen(buf) > (MSG_LEN - sizeof(hdr))) {
                buf[MSG_LEN - sizeof(hdr) - 3] = '"';
                buf[MSG_LEN - sizeof(hdr) - 2] = '\0';
        }

        toc_debug_printf("%s [Len %d]\n", buf, strlen(buf));

	
	if (olen < 0)
		len = escape_message(buf);
	else
		len = olen;
	hdr.ast = '*';
	hdr.type = type;
	hdr.seqno = htons(seqno++ & 0xffff);
        hdr.len = htons(len + (type == TYPE_SIGNON ? 0 : 1));

	toc_debug_printf("Escaped message is '%s'\n",buf);

	memcpy(obuf, &hdr, sizeof(hdr));
	slen += sizeof(hdr);
	memcpy(&obuf[slen], buf, len);
	slen += len;
	if (type != TYPE_SIGNON) {
		obuf[slen]='\0';
		slen += 1;
	}
	/* print_buffer(obuf, slen); */

	return write(toc_fd, obuf, slen);
}

unsigned char *roast_password(char *pass)
{
	/* Trivial "encryption" */
	static char rp[256];
	static char *roast = ROAST;
	int pos=2;
	int x;
	strcpy(rp, "0x");
	for (x=0;(x<150) && pass[x]; x++) 
		pos+=sprintf(&rp[pos],"%02x", pass[x] ^ roast[x % strlen(roast)]);
	rp[pos]='\0';
        return rp;
}

char *print_header(void *hdr_v)
{
	static char s[80];
	struct sflap_hdr *hdr = (struct sflap_hdr *)hdr_v;
	snprintf(s,sizeof(s), "[ ast: %c, type: %d, seqno: %d, len: %d ]",
		hdr->ast, hdr->type, ntohs(hdr->seqno), ntohs(hdr->len));
	return s;
}

int toc_callback(int fd)
{
        char *buf;
	char *c;
	char **args = NULL;
	char *dup,*raw;
        char *l;
	int numargs =0;

        buf = malloc(BUF_LONG);

        if (wait_reply(buf, BUF_LONG) < 0) {
                toc_signoff();
		toc_debug_printf("need to do proper sign off on this\n");
		toc_msg_printf(TOC_CONNECT_MSGS,"Connection Closed");
		return -1;
        }
                         
        dup = strdup(buf+sizeof(struct sflap_hdr));
	raw = rindex(dup,':'); 
	c=strtok(buf+sizeof(struct sflap_hdr),":");	/* Ditch the first part */
	if (!strcasecmp(c,"UPDATE_BUDDY")) {
		char *uc, *t;
		int logged, evil, idle, type = 0;
                time_t signon;
                time_t time_idle;

		numargs = 7;
		args = (char **) malloc(sizeof(char *)*numargs);
		use_handler(TOC_RAW_HANDLE,TOC_UPDATE_BUDDY,raw);
		c = strtok(NULL,":"); /* c is name */
		args[0] = strdup(c);
		
		l = strtok(NULL,":"); /* l is T/F logged status */
       		args[1] = strdup(l);
	
		t = strtok(NULL, ":");
		args[2] = strdup(t);
		sscanf(t, "%d", &evil);
		
		t = strtok(NULL, ":");
		args[3] = strdup(t);		
		sscanf(t, "%ld", &signon);

		t = strtok(NULL, ":");
		args[4] = strdup(t);		
		sscanf(t, "%d", &idle);
		
                uc = strtok(NULL, ":");
		args[5] = strdup(uc);

		if (!strncasecmp(l,"T",1))
			logged = 1;
		else
			logged = 0;


		if (uc[0] == 'A')
			type |= UC_AOL;
		
		switch(uc[1]) {
		case 'A':
			type |= UC_ADMIN;
			break;
		case 'U':
			type |= UC_UNCONFIRMED;
			break;
		case 'O':
			type |= UC_NORMAL;
			break;
		default:
			break;
		}

                switch(uc[2]) {
		case 'U':
			type |= UC_UNAVAILABLE;
			break;
		default:
			break;
		}

                if (idle) {
                        time(&time_idle);
                        time_idle -= idle*60;
                } else
                        time_idle = 0;
		
		serv_got_update(c, logged, evil, signon, time_idle, type); 
		args[6] = NULL;
		use_handler(TOC_HANDLE,TOC_UPDATE_BUDDY,args);
	} else if (!strcasecmp(c, "ERROR")) {
		use_handler(TOC_RAW_HANDLE,TOC_ERROR,raw);
		c = strtok(NULL,":");
		translate_toc_error_code(c);
		args = (char **) malloc(sizeof(char *)*1 + 1);
		numargs = 1;
		args[0] = strdup(c);
		use_handler(TOC_HANDLE,TOC_ERROR,args);
		toc_debug_printf("ERROR: %s",c);
	} else if (!strcasecmp(c, "NICK")) {
		use_handler(TOC_RAW_HANDLE,TOC_NICK,raw);
		c = strtok(NULL,":");
		snprintf(aim_username, sizeof(aim_username), "%s", c);
		numargs = 2;
		args = (char **) malloc(sizeof(char *)*numargs);
		args[0] = strdup(c);
		args[1] = NULL;
		use_handler(TOC_HANDLE,TOC_NICK,args);	
	} else if (!strcasecmp(c, "IM_IN")) {
		char *away, *message;
                int a = 0;
		use_handler(TOC_RAW_HANDLE,TOC_IM_IN,raw);
		c = strtok(NULL,":");
		away = strtok(NULL,":");

		message = away;

                while(*message && (*message != ':'))
                        message++;

                message++;

		if (!strncasecmp(away, "T", 1))
			a = 1;

		if ( serv_got_im(c, message,a) > 0 ) {
			numargs = 3;
			args = (char **) malloc(sizeof(char *)*numargs);		
			args[0] = strdup(c);
			args[1] = strdup(message);
			args[2] = NULL;
			use_handler(TOC_HANDLE,TOC_IM_IN,args);
		}
	} else if (!strcasecmp(c, "GOTO_URL")) {
		char *name;
		char *url;

		char tmp[256];
		
		use_handler(TOC_RAW_HANDLE,TOC_GOTO_URL,raw);
		name = strtok(NULL, ":");
		url = strtok(NULL, ":");


		snprintf(tmp, sizeof(tmp), "http://%s:%d/%s", toc_addy, aim_port, url);
/*		fprintf(stdout, "Name: %s\n%s\n", name, url);
		printf("%s", grab_url(tmp));*/

		numargs = 2;
		args = (char **) malloc(sizeof(char *)*numargs);
		args[0] = strdup(tmp);
		args[1] = NULL;
		use_handler(TOC_HANDLE,TOC_GOTO_URL,args);
		/* statusprintf("GOTO_URL: %s","tmp"); */
        } else if (!strcasecmp(c, "EVILED")) {
                int lev;
		char *name = NULL;
		char *levc;

		use_handler(TOC_RAW_HANDLE,TOC_EVILED,raw);
		levc = strtok(NULL, ":");
                sscanf(levc, "%d", &lev);
                name = strtok(NULL, ":");

                toc_debug_printf("evil: %s | %d\n", name, lev);

		numargs = 3;
		my_evil = lev;
		args = (char **) malloc(sizeof(char *)*numargs);		
		if ( name != NULL )
			args[0] = strdup(name);
		else 
			args[0] = NULL;
		args[1] = strdup(levc);
		args[2] = NULL;
		use_handler(TOC_HANDLE,TOC_EVILED,args);
		
        } else if (!strcasecmp(c, "CHAT_JOIN")) {
                char *name,*idc;
                int id;
		
                use_handler(TOC_RAW_HANDLE,TOC_CHAT_JOIN,raw);
		idc = strtok(NULL, ":");
		sscanf(idc, "%d", &id);
                name = strtok(NULL, ":");
                serv_got_joined_chat(id, name); 
		numargs = 3;
		args = (char **) malloc(sizeof(char *)*numargs);		
		args[0] = strdup(idc);
		args[1] = strdup(name);
		args[2] = NULL;
		use_handler(TOC_HANDLE,TOC_CHAT_JOIN,args);		
	} else if (!strcasecmp(c, "DIR_STATUS")) {
		char *status;
		use_handler(TOC_RAW_HANDLE,TOC_DIR_STATUS,raw);
		status = strtok(NULL,":");
		numargs = 2;
		args = (char **) malloc(sizeof(char *)*numargs);		
		args[0] = strdup(status);
		args[1] = NULL;		
		use_handler(TOC_HANDLE,TOC_DIR_STATUS,args);		
	} else if (!strcasecmp(c, "CHAT_UPDATE_BUDDY")) {
		int id;
		char *in,*idc;
		char *buddy;
                LLE t;
		struct buddy_chat *b = NULL;
	
		use_handler(TOC_RAW_HANDLE,TOC_CHAT_UPDATE_BUDDY,raw);		
		idc = strtok(NULL, ":");
		sscanf(idc, "%d", &id);

		in = strtok(NULL, ":");

		for ( TLL(buddy_chats,t) ) {
			b = (struct buddy_chat *)t->data;
			if (id == b->id)
				break;	
                        b = NULL;
		}
		
		if (!b)
			return -2;

		
		if (!strcasecmp(in, "T")) {
			while((buddy = strtok(NULL, ":")) != NULL) {
				/* 
				 * Fuxin aim causes a problem here
				 */
				AddToLL(b->in_room, buddy,NULL);
				if ( b->init_chat ) {
					args = (char **) malloc(sizeof(char *)*3);
					args[0] = strdup(b->name);
					args[1] = strdup(buddy);		
					args[2] = NULL;					
					use_handler(TOC_HANDLE,TOC_BUDDY_JOIN_CHAT,args);
					free(args[0]); free(args[1]); free(args); args = NULL;
				}
			}
			/*
			 * init_chat is so that the user doenst get flooded 
			 * with user joined chat when he first joins a chat
			 */
			b->init_chat = 1;				
		} else {
			while((buddy = strtok(NULL, ":")) != NULL) {
				RemoveFromLLByKey(b->in_room, buddy);
				/* 
				 * Since we might get multiple leave/joins at once 
				 * we allocate & deallocate here 
				 */
				args = (char **) malloc(sizeof(char *)*3);
				args[0] = strdup(b->name);
				args[1] = strdup(buddy);		
				args[2] = NULL;					
				use_handler(TOC_HANDLE,TOC_BUDDY_LEFT_CHAT,args);
				free(args[0]); free(args[1]); free(args); args = NULL;
			}
		}
	} else if (!strcasecmp(c, "CHAT_LEFT")) {
		char *idc;
		int id;

		use_handler(TOC_RAW_HANDLE,TOC_CHAT_LEFT,raw);
		idc = strtok(NULL, ":");
                sscanf(idc, "%d", &id);

                serv_got_chat_left(id); 

		numargs = 2;
		args = (char **) malloc(sizeof(char *)*numargs);
		args[0] = strdup(idc);	
		args[1] = NULL;
		use_handler(TOC_HANDLE,TOC_CHAT_LEFT,args);		
	} else if (!strcasecmp(c, "CHAT_IN")) {

		int id, w;
		char *m,*idc;
		char *who, *whisper, *chan;
		struct buddy_chat *b;		

		use_handler(TOC_RAW_HANDLE,TOC_CHAT_IN,raw);
		idc = strtok(NULL, ":");
		sscanf(idc, "%d", &id);
		who = strtok(NULL, ":");
		whisper = strtok(NULL, ":");
		m = whisper;
                while(*m && (*m != ':')) m++;
                m++;

                if (!strcasecmp(whisper, "T"))
			w = 1;
		else
			w = 0;

		/* serv_got_chat_in(id, who, w, m); */
		b = buddy_chat_getbyid(id);
		if ( ! b ) {
			chan = (char *) malloc(50);
			strcpy(chan,"ERROR Couldn't lookup chan!");
		} else {
			chan = (char *) malloc(strlen(b->name)+1);
			strcpy(chan,b->name);
		}
		numargs = 6;
		args = (char **) malloc(sizeof(char *)*numargs);
		args[0] = strdup(idc);
		args[1] = strdup(who);
		args[2] = strdup(whisper);
		args[3] = strdup(m);
		/* Added arg to make things simple */
		args[4] = chan;
		args[5] = NULL;
		use_handler(TOC_HANDLE,TOC_CHAT_IN,args);
	} else if (!strcasecmp(c, "CHAT_INVITE")) {
		char *name;
		char *who;
		char *message,*idc;
                int id, *pid;

                use_handler(TOC_RAW_HANDLE,TOC_CHAT_INVITE,raw);
		name = strtok(NULL, ":");
		idc = strtok(NULL, ":");
		sscanf(idc, "%d", &id);
		who = strtok(NULL, ":");
                message = strtok(NULL, ":");	
               /* serv_got_chat_invite(name, id, who, message); */
	        pid = (int *) malloc(sizeof(int));
		*pid = id;
	        AddToLL(invited_chats,name,pid);
		numargs = 5;
		args = (char **) malloc(sizeof(char *)*numargs);
		args[0] = strdup(name);
		args[1] = strdup(idc);
		args[2] = strdup(who);
		args[3] = strdup(message);
		args[4] = NULL;
		use_handler(TOC_HANDLE,TOC_CHAT_INVITE,args);	       
	} else {
		toc_debug_printf("don't know what to do with %s\n", c);
	}
	free(dup);
        free(buf);
	if ( args != NULL ) {
		int x;
		/* toc_debug_printf("\nGOING TO FREE!: numargs = %d",numargs); */
		for (x=0;x< numargs; x++) 
			if ( args[x] != NULL ) {
				/* toc_debug_printf("freeing %d",x); */
				free(args[x]);
			}
		/* toc_debug_printf(""); */
		free(args);	
	}
	return 1;
}

char *toc_wait_config()
{
	/* Waits for configuration packet, returning the contents of the packet */
	static char buf[BUF_LEN];
	int res;
        res = wait_reply(buf, sizeof(buf));
	if (res < 0)
		return NULL;
	if (state != STATE_CONFIG) {
     		toc_debug_printf("State should be %d, but is %d instead\n",STATE_CONFIG, state);
		return NULL;
	}
	/* At this point, it's time to setup automatic handling of incoming packets */
        state = STATE_ONLINE;
	
        // inpa = gdk_input_add(toc_fd, GDK_INPUT_READ | GDK_INPUT_EXCEPTION, toc_callback, NULL);
	toc_add_input_stream(toc_fd,&toc_callback);
	
	return buf;
}

void parse_toc_buddy_list(char *config)
{
	char *c;
        char current[256];
	char *name;
	LL bud = CreateLL();		
        
        /* skip "CONFIG:" (if it exists)*/

        c = strncmp(config + sizeof(struct sflap_hdr),"CONFIG:",strlen("CONFIG:"))?
			strtok(config, "\n"):
			strtok(config + sizeof(struct sflap_hdr)+strlen("CONFIG:"), "\n");
	
	do {
		if (c == NULL) 
			break;
		if (*c == 'g') {
			strncpy(current,c+2, sizeof(current));
			add_group(current);
		} else if (*c == 'b') {
			add_buddy(current, c+2);
			AddToLL(bud, c+2, NULL);
        	} else if (*c == 'p') {
           		name = malloc(strlen(c+2) + 2);
			snprintf(name, strlen(c+2) + 1, "%s", c+2);
			AddToLL(permit, name, NULL);
		} else if (*c == 'd') {
			name = malloc(strlen(c+2) + 2);
			snprintf(name, strlen(c+2) + 1, "%s", c+2);
			AddToLL(deny, name,NULL);
		} else if (*c == 'm') {
 			sscanf(c + strlen(c) - 1, "%d", &permdeny);
			if (permdeny == 0)
				permdeny = PERMIT_PERMITALL;
		}
	} while ((c=strtok(NULL,"\n"))); 
       
	serv_add_buddies(bud);
	FreeLL(bud);
        serv_set_permit_deny();
}

int toc_signoff() {	
	/* Leaking memory like a MOFO */
	FreeLL(groups);
	FreeLL(buddy_chats);
	FreeLL(invited_chats);
	FreeLL(permit);
	FreeLL(deny);
	deny = groups = permit = buddy_chats = invited_chats = NULL;
	toc_debug_printf("LEAKING MEMORY LIKE A BITCH in toc_signoff!");

	serv_close();
	toc_msg_printf(TOC_CONNECT_MSGS,"%s signed off",aim_username);
	return 1;
}

void toc_build_config(char *s, int len)
{
	struct group *g;
	struct buddy *b;
	LLE t,t1;
	LL mem;

	int pos=0;
	toc_debug_printf("FIX this permdeny hack shit!");

	if (!permdeny)
		    permdeny = PERMIT_PERMITALL;
	pos += snprintf(&s[pos], len - pos, "m %d\n", permdeny);
	
	/* Create Buddy List */
	for ( TLL(groups,t) ) {
		g = (struct group *)t->data;
		pos += snprintf(&s[pos], len - pos, "g %s\n", g->name);
		mem = g->members;
		for ( TLL(mem,t1) ) {
			b = (struct buddy *)t1->data;
			pos += snprintf(&s[pos], len - pos, "b %s\n", b->name);
		}
	}
	
	/* Create Permit and Deny Lists */;
	for ( TLL(permit,t) ) {
		toc_debug_printf("permit: added %s\n",(char *)t->key);
    		pos += snprintf(&s[pos], len - pos, "p %s\n", (char *)t->key);
	}
	for ( TLL(deny,t) ) {
		toc_debug_printf("deny: added %s\n",(char *)t->key);
    		pos += snprintf(&s[pos], len - pos, "d %s\n", (char *)t->key);
	}	
}

void translate_toc_error_code(char *c) {

	int no = atoi(c);
	char *w = strtok(NULL, ":");
	char buf[256];

        switch ( no ) {
        	case 901:
                	snprintf(buf, sizeof(buf), "%s not currently logged in.", w);
	                break;
        	case 902:
	                snprintf(buf, sizeof(buf), "Warning of %s not allowed.", w);
        	        break;
	        case 903:
        	        snprintf(buf, sizeof(buf), "A message has been dropped, you are exceeding the server speed limit.");
                	break;
	        case 950:
        	        snprintf(buf, sizeof(buf), "Chat in %s is not available.", w);
                	break;
	        case 960:
        	        snprintf(buf, sizeof(buf), "You are sending messages too fast to %s.", w);
                	break;
	        case 961:
        	        snprintf(buf, sizeof(buf), "You missed an IM from %s because it was too big.", w);
                	break;
	        case 962:
	                snprintf(buf, sizeof(buf), "You missed an IM from %s because it was sent too fast.", w);
                	break;
	        case 970:
        	        snprintf(buf, sizeof(buf), "Failure.");
                	break;
	        case 971:
        	        snprintf(buf, sizeof(buf), "Too many matches.");
                	break;
	        case 972:
        	        snprintf(buf, sizeof(buf), "Need more qualifiers.");
                	break;
        	case 973:
	                snprintf(buf, sizeof(buf), "Dir service temporarily unavailable.");
        	        break;
	        case 974:
	                snprintf(buf, sizeof(buf), "Email lookup restricted.");
        	        break;
	        case 975:
                	snprintf(buf, sizeof(buf), "Keyword ignored.");
        	        break;
	        case 976:
         	       snprintf(buf, sizeof(buf), "No keywords.");
                	break;
	        case 977:
                	snprintf(buf, sizeof(buf), "User has no directory information.");
        	        /* snprintf(buf, sizeof(buf), "Language not supported."); */
	                break;
        	case 978:
                	snprintf(buf, sizeof(buf), "Country not supported.");
	                break;
        	case 979:
                	snprintf(buf, sizeof(buf), "Failure unknown: %s.", w);
	                break;
        	case 980:
                	snprintf(buf, sizeof(buf), "Incorrect nickname or password.");
	                break;
	        case 981:
        	        snprintf(buf, sizeof(buf), "The service is temporarily unavailable.");
                	break;
	        case 982:
        	        snprintf(buf, sizeof(buf), "Your warning level is currently too high to log in.");
                	break;
	        case 983:
        	        snprintf(buf, sizeof(buf), "You have been connecting and disconnecting too frequently.  Wait ten minutes and try again.  If you continue to try, you will need to wait even longer.");
                	break;
	        case 989:
        	        snprintf(buf, sizeof(buf), "An unknown signon error has occurred: %s.", w);
                	break;
	        default:
        	        snprintf(buf, sizeof(buf), "An unknown error, %d, has occured.  Info: %s", no, w);
	}
	toc_msg_printf(TOC_TRANSLATED_ERROR,buf);
        return;
}

--- NEW FILE: misc.c ---
/*
 * misc.c
 *
 * by Nadeem Riaz (nads at bleh.org)
 */

#include "toc.h"

char aim_host[512];
int aim_port;
char login_host[512];
int login_port;
char toc_addy[16];
char aim_username[80];
char aim_password[16];
char *quad_addr;
char debug_buff[1024];
char user_info[2048];
int registered;

char *USER_CLASSES[5] = {
	"AOL User",
	"AIM Admin",
	"Trial Aim User",
	"Normal Aim User",
	"Unavailable"
};

char *PERMIT_MODES[4] = {
	"Permit All",
	"Deny All",
	"Permit Some",
	"Deny Some"
};	

void save_prefs()
{ 
}

void misc_free_group(void *data) {
	struct group *g;
	g = (struct group *) data;
	FreeLL(g->members);
	free(g);
}

void misc_free_buddy_chat(void *data) {
	struct buddy_chat *b;
	b = (struct buddy_chat *) data;
	FreeLL(b->in_room);
	FreeLL(b->ignored);
	free(b);
}

void misc_free_invited_chats(void *data) {
	int *t;
	t = (int *) data;
	free(t);
}

--- NEW FILE: Makefile.in ---
SHELL = @SHELL@

srcdir = @srcdir@
VPATH = @srcdir@
top_srcdir = @top_srcdir@
topdir = @topdir@
prefix = @prefix@
exec_prefix = @exec_prefix@

bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = @oldincludedir@

local_dir = $(HOME)

# Where the BitchX binary will be installed.
# "make install" will compile and install the program.
INSTALL_IRC = @INSTALL_IRC@

# Where the BitchX library will be. Generally this is the place that
# you put the scripts, help pages and translation tables. It is
# very important that you set this correctly.
IRCLIB = @IRCLIB@

CC = @CC@
DEFS = @INCLUDES@
LIBS = @LIBS@

# Tcl library.
TCL_LIBS = @TCL_LIBS@

# These are for Tcl support.
TCL_OBJS = @TCL_OBJS@
# You don't have the following, so you'll want to leave this blank.
TCL_SRCS = @TCL_SRCS@

# Set this to -g if you want to be able to debug the client, otherwise
# use -O to have the compiler do some optimization instead.
CFLAGS = @CFLAGS@

# Set this to -s if you want the binary to be stripped.
LDFLAGS = @LDFLAGS@

# These are for the cd device player.
CD_SRCS = @CD_SRCS@
CD_OBJS = @CD_OBJS@

# This is the executable suffix for the target operating system.
EXEEXT = @EXEEXT@

# Extra files.
DEFAULT_CTOOLZ_DIR = @DEFAULT_CTOOLZ_DIR@
DEFAULT_MSGLOGFILE = @DEFAULT_MSGLOGFILE@
DEFAULT_BITCHX_HELP_FILE = @DEFAULT_BITCHX_HELP_FILE@
DEFAULT_SCRIPT_HELP_FILE = @DEFAULT_SCRIPT_HELP_FILE@
DEFAULT_BITCHX_KICK_FILE = @DEFAULT_BITCHX_KICK_FILE@
DEFAULT_BITCHX_QUIT_FILE = @DEFAULT_BITCHX_QUIT_FILE@
DEFAULT_BITCHX_IRCNAME_FILE = @DEFAULT_BITCHX_IRCNAME_FILE@

# Full path of the directory for BitchX help files.
HELPDIR = @HELPDIR@

# Full path of the directory for the BitchX scripts.
INSTALL_SCRIPT = @INSTALL_SCRIPT@

# Default setting for IRCPATH where BitchX will look for
# its script files if the environment variable is undefined.
# Usually, this should contain the same path as used for INSTALL_SCRIPT in
# the Makefile, but it can contain multiple path elements
# separated by colons. The path MUST lead to an existing directory,
# because the 'global' script is expected to be found there.
IRCPATH = @IRCPATH@

# Path for TRANSLATION variable.
TRANSLATION_PATH = @TRANSLATION_PATH@

# This command will be used to install the BitchX help files. If you don't
# want to install them, replace with the following:
# INSTALL_HELP_CMD = @echo The help files have not been installed.
INSTALL_HELP_CMD = @INSTALL_HELP_CMD@

# This is where the optional plugins will be copied to.
PLUGINDIR = @PLUGINDIR@

# Plugin flags.
SHLIB_LD = @SHLIB_LD@
SHLIB_CFLAGS = @SHLIB_CFLAGS@
SHLIB_SUFFIX = @SHLIB_SUFFIX@

# This command will be used to install the BitchX files on Win32/OS2EMX
# systems.
WINNT_INSTALL = @WINNT_INSTALL@

# This program allows you to use screen/xterm's to put new BitchX windows
# on new screen/xterm windows.
INSTALL_WSERV = @INSTALL_WSERV@

# This program allows you to screen BitchX and reattach to it later.
INSTALL_SCRBX = @INSTALL_SCRBX@

# Set gzip and bzip2 options.
GZIP_ENV = @GZIP_ENV@
BZIP2 = @BZIP2@

# Standard programs.
RM = @RM@
LN = @LN_S@
CP = @CP@
MV = @MV@

INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@

VERSION = @VERSION@
_VERSION_ = @_VERSION_@

MAKE_BIN = @MAKE@
MAKE = $(MAKE_BIN) $(MFLAGS)
MFLAGS = \
	'local_dir=$(HOME)'			\
	'INSTALL_IRC=$(INSTALL_IRC)'		\
	'IRCLIB=$(IRCLIB)'			\
	'CC=$(CC)'				\
	'CFLAGS=$(CFLAGS)'			\
	'HELPDIR=$(HELPDIR)'			\
        'INSTALL_WSERV=$(INSTALL_WSERV)'	\
	'IRCPATH=$(IRCPATH)'			\
	'TRANSLATION_PATH=$(TRANSLATION_PATH)'	\
	'LDFLAGS=$(LDFLAGS)'			\
	'LIBS=$(LIBS)'				\
	'LN=$(LN)'				\
	'RM=$(RM)'				\
	'TCL_SRCS=$(TCL_SRCS)'			\
	'TCL_OBJS=$(TCL_OBJS)'			\
	'CD_PLAY=$(CD_PLAY)'			\
	'CD_SRCS=$(CD_SRCS)'			\
	'CD_OBJS=$(CD_OBJS)'			\
	'TCL_LIBS=$(TCL_LIBS)'			\
	'PLUGINDIR=$(PLUGINDIR)'		\
	'_VERSION_=$(_VERSION_)'		\
	'VERSION=$(VERSION)'			\
	'INSTALL_DATA=$(INSTALL_DATA)'		\
	'INSTALL_SCRIPT=$(INSTALL_SCRIPT)'	\
	'EXEEXT=$(EXEEXT)'			\
	'SHLIB_CFLAGS=$(SHLIB_CFLAGS)'		\
	'SHLIB_SUFFIX=$(SHLIB_SUFFIX)'

## Makefile starts here.

#DEBUG_CFLAGS = -g -DDEBUG_LIB_TOC

.c.o:
	$(CC) $(DEFS) $(CFLAGS) $(DEBUG_CFLAGS)  -c $<

LOBJS = toc.o network.o util.o server.o interface.o buddy.o ll.o misc.o

all: libtoc.a

libtoc.a: $(LOBJS)
	ar cru libtoc.a $(LOBJS)

Makefile: Makefile.in
	cd $(topdir) \
	  && ./config.status

clean:
	$(RM) $(LOBJS) libtoc.a

distclean: clean
	$(RM) Makefile

--- NEW FILE: buddy.c ---
/*
 * gaim
 *
 * Copyright (C) 1998-1999, Mark Spencer <markster at marko.net>
 *
 * 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
 * 
 */


/* 
 * Heavily modified by Nadeem Riaz (nads at bleh.org)
 * for use in libtoc
 */


#include <string.h>
#include "ll.h"
#include "toc.h"

LL groups;
LL permit;
LL deny;  
LL buddy_chats;
LL invited_chats;

struct buddy *add_buddy(char *group, char *buddy)
{
	struct buddy *b;
	struct group *g;
	
	toc_debug_printf("adding '%s' to '%s'\n",buddy,group);

	if ((b = find_buddy(buddy)) != NULL)
                return b;

	g = find_group(group);

	if (g == NULL)
		g = add_group(group);
	
        b = (struct buddy *)  malloc(sizeof(struct buddy));
        
	if (!b)
		return NULL;

	b->present = 0;

	snprintf(b->name, sizeof(b->name), "%s", buddy);
	AddToLL(g->members,b->name,b);
       
        b->idle = 0;
	
	return b;
}

struct group *add_group(char *group)
{
	struct group *g;
	g = (struct group *) malloc(sizeof(struct group));
	if (!g)
		return NULL; 

	strncpy(g->name, group, sizeof(g->name));
        AddToLL(groups, g->name, g);
	
	g->members = CreateLL();
	
	return g;	
}

struct group *find_group(char *group)
{
	struct group *g;
	LLE e;
	char *grpname = malloc(strlen(group) + 1);
	strcpy(grpname, normalize(group));
	
	for ( TLL(groups,e) ) {
		g = (struct group *)e->data;
		if (!strcasecmp(normalize(g->name), grpname)) {
			free(grpname);
			return g;
		}
	}

	free(grpname);
	return NULL;	
	
}

struct buddy *find_buddy(char *who)
{
	struct group *g;
	struct buddy *b;
	LLE tg,tb;
	LL mems;
        char *whoname = malloc(strlen(who) + 1);

	strcpy(whoname, normalize(who));
	
	for ( TLL(groups,tg) ) {
		g = (struct group *) tg->data;
		mems =  g->members;
		
		for ( TLL(mems,tb) )  {
			b = (struct buddy *)tb->data;
			if (!strcasecmp(normalize(b->name), whoname)) {
				free(whoname);
				return b;
			}
		}
		
	}
	
	free(whoname);
	return NULL;
}

int user_remove_buddy(char *buddy) {
	struct group *g;
	struct buddy *b;
	LLE e,m;
	char *budname = malloc(strlen(buddy) + 1);
	strcpy(budname, normalize(buddy));
	
	for ( TLL(groups,e) ) {
		g = (struct group *)e->data;
		
		for ( TLL(g->members,m) ) {
			b = (struct buddy *)m->data;
			if ( ! strcasecmp(normalize(b->name),budname) ) {
				RemoveFromLLByKey(g->members,buddy);
				serv_remove_buddy(buddy);
				serv_save_config();
				free(budname);				
				return 1;
			}
		}
	}

	free(budname);
	return -1;	
}

int user_add_buddy(char *group, char *buddy) {
	struct buddy *b;
	b = find_buddy(buddy);
	if ( b != NULL )
		return -1;
	add_buddy(group,buddy);
	serv_add_buddy(buddy);
	serv_save_config();
	return 1; 
}

/* 
 * mode 1 = move current group members to a enw group
 * mode 2 = delete current group members from buddy list
 */
int remove_group(char *group, char *newgroup, int mode)
{
	LL mem;
	LLE t;
	
	struct group *delg = find_group(group);
	struct group *newg = NULL;
	struct buddy *delb;

	if ( ! delg ) {		
		return -1;
	}
	
	if ( mode == 1 ) {
		newg = find_group(newgroup);
		if ( ! newg ) {
			newg = add_group(newgroup);
		}
	}

        mem = delg->members; 
	for ( TLL(mem,t) ) {
		delb = (struct buddy *)t->data;
		if ( mode == 1 ) { 
			AddToLL(newg->members,delb->name,delb);
		} else {
        	        serv_remove_buddy(delb->name);
                	/* free(delb); */
		}
	}

	RemoveFromLLByKey(groups,delg->name);
        serv_save_config();
	return 1;
}

int add_permit(char *sn) {
	LLE t;
	t = FindInLL(permit,sn);
	if ( t ) 
		return -1;
	AddToLL(permit,sn,NULL);
	if ( permdeny == PERMIT_PERMITSOME )
		serv_add_permit(sn);
	serv_save_config();
	return 1;
}

int remove_permit(char *sn) {
	LLE t;
	t = FindInLL(permit,sn);
	if ( ! t ) 
		return -1;
	RemoveFromLLByKey(permit,sn);
	serv_save_config();	
	if (permdeny == PERMIT_PERMITSOME ) 
		serv_set_permit_deny();	
	return 1;
}

int add_deny(char *sn) {
	LLE t;
	t = FindInLL(deny,sn);
	if ( t ) 
		return -1;
	AddToLL(deny,sn,NULL);
	if ( permdeny == PERMIT_DENYSOME )
		serv_add_deny(sn);
	serv_save_config();
	return 1;
}

int remove_deny(char *sn) {
	LLE t;
	t = FindInLL(deny,sn);
	if ( ! t ) 
		return -1;
	RemoveFromLLByKey(deny,sn);
	if ( permdeny == PERMIT_DENYSOME ) {
		/* 
		 * DAMN AOL HOEBAGS to lazzy toinclude a delete from deny list
		 * Thus we need to first go into permit mode */
		serv_set_permit_deny();
	}
	serv_save_config();	
	return 1;	
}

int buddy_invite(char *chat, char *buddy, char *msg) {
	LLE t;
	struct buddy_chat *b;
	t = FindInLL(buddy_chats,chat);
	if ( ! t ) 
		return -1;
	b = (struct buddy_chat *)t->data;
	serv_chat_invite(b->id, msg, buddy);
	return 1;
}

/*
 * Checks invite list first 
 * then tries to create chat
 */
 
void buddy_chat_join(char *chan) {
	LLE t = FindInLL(invited_chats,chan);
	if ( ! t ) {
		/* Standard exchange is 4 */
		toc_debug_printf("Creating chan %s",chan);
		serv_join_chat(4,chan);
	} else {
		/* The chat is in our invite list */
		int *d;
		d = (int *) t->data;
		serv_accept_chat(*d);
		toc_debug_printf("Trying to join invited to %s %d",t->key, *d);
		RemoveFromLLByKey(invited_chats,chan);		
	}
}

struct buddy_chat *find_buddy_chat(char *chat) {
	LLE t;
	t = FindInLL(buddy_chats,chat);
	if ( ! t ) 
		return NULL;
	else
		return (struct buddy_chat *) t->data;
}

int buddy_chat_leave(char *chan) {
	LLE t;
	struct buddy_chat *b;
	t = FindInLL(buddy_chats,chan);	
	if ( ! t ) 
		return -1;
	b = (struct buddy_chat *) t->data;
	serv_chat_leave(b->id);
	/* Removed from buddy_chats in toc_callback */	
	return 1;
}

struct buddy_chat *buddy_chat_getbyid(int id) {
	LLE t;
	struct buddy_chat *b;
	for ( TLL(buddy_chats,t) ) {
		b = (struct buddy_chat *) t->data;
		if ( id == b->id ) 
			return b;
	}	
	return NULL;		
}

int buddy_chat_invite(char *chat, char *buddy, char *msg) {
	LLE t;
	struct buddy_chat *b;
	t = FindInLL(buddy_chats,chat);	
	if ( ! t ) 
		return -1;
	b = (struct buddy_chat *) t->data;
	serv_chat_invite(b->id, msg, buddy);
	return 1;
}

int buddy_chat_warn(char *chat, char *user, int anon) {
	LLE t;
	struct buddy_chat *b;
	t = FindInLL(buddy_chats,chat);	
	if ( ! t ) 
		return -1;
	b = (struct buddy_chat *) t->data;	
	serv_chat_warn(b->id, user, anon);
	return 1;
}

--- NEW FILE: toc.h ---
#ifndef _TOC_H
#define _TOC_H

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include "ll.h"

/* TOC DEFS */
#define FLAPON "FLAPON\r\n\r\n"
#define MSG_LEN 2048
#define BUF_LEN MSG_LEN
#define MAX_OUTPUT_MSG_LEN 4096
#define BUF_LONG BUF_LEN * 2
#define LANGUAGE "english"
#define REVISION "gaim-libtoc:$Revision: 1.1.1.1 $"
#define ROAST "Tic/Toc"
#define TOC_HOST "toc.oscar.aol.com"
#define TOC_PORT 9898
#define AUTH_HOST "login.oscar.aol.com"
#define AUTH_PORT 5190
#define LAGOMETER_STR "123CHECKLAG456"

/* connection states */
#define STATE_OFFLINE 0
#define STATE_FLAPON 1
#define STATE_SIGNON_REQUEST 2
#define STATE_SIGNON_ACK 3
#define STATE_CONFIG 4
#define STATE_ONLINE 5

/* communication types */
#define TYPE_SIGNON    1  
#define TYPE_DATA      2
#define TYPE_ERROR     3
#define TYPE_SIGNOFF   4
#define TYPE_KEEPALIVE 5

/* permit modes */
#define PERMIT_PERMITALL  1
#define PERMIT_DENYALL    2
#define PERMIT_PERMITSOME 3
#define PERMIT_DENYSOME   4

/* User Types */
#define UC_AOL		1
#define UC_ADMIN 	2
#define UC_UNCONFIRMED	4
#define UC_NORMAL	8
#define UC_UNAVAILABLE  16


/* INTERFACE */

#define TOC_HANDLE 			1
#define TOC_RAW_HANDLE  		2

/* The following can be handlers in either normal or raw mode */

#define TOC_SIGN_ON			0
#define TOC_CONFIG			1
#define TOC_NICK 			2
#define TOC_IM_IN			3
#define TOC_UPDATE_BUDDY		4
#define TOC_ERROR			5
#define TOC_EVILED			6
#define TOC_CHAT_JOIN			7
#define TOC_CHAT_IN			8
#define TOC_CHAT_UPDATE_BUDDY		9
#define TOC_CHAT_INVITE			10
#define TOC_CHAT_LEFT			11
#define TOC_GOTO_URL 			12
#define TOC_DIR_STATUS			13

/* TEMP */
#define TOC_REINSTALL_TIMER		19

/* Special HANDLES -- can only be used in Normal mode */
		
#define TOC_SOCKFD			20
#define TOC_RM_SOCKFD			21
#define TOC_RECIEVED_IM 		TOC_IM_IN
#define TOC_BUDDY_LOGGED_ON		22
#define TOC_BUDDY_LOGGED_OFF		23
#define TOC_CONNECT_MSGS 		24
#define TOC_TRANSLATED_ERROR		25
#define TOC_BUDDY_LEFT_CHAT		26
#define TOC_BUDDY_JOIN_CHAT		27
#define TOC_LAG_UPDATE			28
#define TOC_WENT_IDLE			29


#define TOC_DEBUG_LOG "/tmp/aim-bx.log"

/* structs */
struct sflap_hdr {
	unsigned char ast;
	unsigned char type;
	unsigned short seqno;
	unsigned short len;
};

struct signon {
	unsigned int ver;
	unsigned short tag;
	unsigned short namelen;
	char username[80];
};


struct buddy {
	char name[80];
        int present;
        int log_timer;
	int evil;
	time_t signon;
	time_t idle;
        int uc;
};


struct group {
	char name[80];
	LL members;
};

struct buddy_chat {
        LL in_room;
        LL ignored;
	int makesound;
        int id;
	int init_chat;
	char name[80];
};



/* toc.c */
int toc_login(char *username, char *password);
int toc_signon(char *username, char *password);
int wait_reply(char *buffer, int buflen);
unsigned char *roast_password(char *pass);
char *print_header(void *hdr_v);
int toc_wait_signon();
char *toc_wait_config();
int sflap_send(char *buf, int olen, int type);
int toc_signoff();
void toc_close();
void toc_build_config(char *s, int len);
void parse_toc_buddy_list(char *);
void translate_toc_error_code(char *c);

extern int toc_fd;
extern int seqno;
extern unsigned int peer_ver;
extern int state;
/* extern int inpa; */


/* util.c */
void set_state(int i);
int escape_message(char *msg);
char *normalize(char *s);
void strdown(char *s);
int escape_text(char *msg);
void toc_debug_printf(char *fmt, ...);
void toc_msg_printf(int type, char *fmt, ...);
char *strip_html(char *text);


/* network.c */
unsigned int *get_address(char *hostname);
int connect_address(unsigned int addy, unsigned short port);


/* server.c */
void serv_finish_login();
void serv_add_buddy(char *name);
void serv_remove_buddy(char *name);
void serv_set_info(char *info);
void serv_get_info(char *name);
int serv_got_im(char *name, char *message, int away);
void serv_add_buddies(LL buddies);
void serv_send_im(char *name, char *message);
void serv_got_update(char *name, int loggedin, int evil, time_t signon, time_t idle, int type);
void serv_close();
void serv_save_config();
void serv_warn(char *name, int anon);
void serv_add_permit(char *);
void serv_add_deny(char *);
void serv_set_permit_deny();
void serv_got_joined_chat(int id, char *name);
void serv_got_chat_left(int id);
void serv_accept_chat(int);
void serv_join_chat(int, char *);
void serv_chat_invite(int, char *, char *);
void serv_chat_leave(int);
void serv_chat_whisper(int, char *, char *);
void serv_chat_send(int, char *);
void serv_chat_warn(int  id, char *user, int anon);
void serv_get_dir(char *name);
void serv_set_dir(char *first, char *middle, char *last, char *maiden, char *city, char *state, char *country, char *email, int web);
void serv_dir_search(char *first, char *middle, char *last, char *maiden, char *city, char *state, char *country, char *email);
void serv_touch_idle();
void serv_set_idle(int time);
int check_idle();
void serv_set_away(char *message);

extern int idle_timer;
extern time_t lastsent;
extern time_t login_time;
extern struct timeval lag_tv;
extern int is_idle;
extern int lag_ms;
extern int permdeny;
extern int my_evil;
extern int is_away;
extern int time_to_idle;


/* misc.c */
void save_prefs();
void misc_free_group(void *);
void misc_free_buddy_chat(void *);
void misc_free_invited_chats(void *);

extern char aim_host[512];
extern int aim_port;
extern char login_host[512];
extern int login_port;
extern char toc_addy[16];
extern char aim_username[80];
extern char aim_password[16];
extern char *quad_addr;
extern char debug_buff[1024];
extern char user_info[2048];
extern int registered;
extern char *USER_CLASSES[5];
extern char *PERMIT_MODES[4];


/* buddy.c */
struct buddy *add_buddy(char *group, char *buddy);
struct buddy *find_buddy(char *who);
struct group *add_group(char *group);
struct group *find_group(char *group);
int user_add_buddy(char *group,char *buddy);
int user_remove_buddy(char *buddy);
int remove_group(char *group, char *newgroup, int mode);
int add_permit(char *sn);
int remove_permit(char *sn);
int add_deny(char *sn);
int remove_deny(char *sn);
int buddy_chat_invite(char *chat, char *buddy, char *msg);
void buddy_chat_join(char *chan);
int buddy_chat_leave(char *chan);
struct buddy_chat *find_buddy_chat(char *chat);
struct buddy_chat *buddy_chat_getbyid(int id);
int buddy_chat_warn(char *chat, char *user, int anon);

extern LL groups;
extern LL permit;  /* The list of people permitted */
extern LL deny;    /* The list of people denied */
extern LL buddy_chats;
extern LL invited_chats;


/* inteface.c */
void init_toc();
void init_lists();
int install_handler(int type, int (*func)(int, char **));
int install_raw_handler(int type, int (*func)(int, char *));
int use_handler(int mode,int type, void *args);

extern int (*TOC_RAW_HANDLERS[30])(int, char *); 
extern int (*TOC_HANDLERS[30])(int, char **);


/* EXTERNAL FUNCTIONS */

extern int toc_add_input_stream(int,int (*)(int));
extern int toc_remove_input_stream(int);	

#endif // _TOC_H

--- NEW FILE: ll.h ---
#ifndef _LL_H
#define _LL_H

/*
 * Really bad list implementation
 */

#define TLL(list,e) e = list->head->next; e; e = e->next

struct _lle {
	char *key;
	void *data;	
	struct _lle *next;
};

typedef struct _lle * LLE;

struct _ll {
	LLE head;
	LLE curr;
	void (*free_e)(void *);
	int items;
	
};

typedef struct _ll * LL;

LL CreateLL();
void SetFreeLLE(LL List, void (*free_e)(void *));
LLE CreateLLE (char *key, void *data, LLE next);
int AddToLL(LL List, char *key, void *data);
LLE FindInLL(LL List, char *key);
void *GetDataFromLLE(LLE e);
int RemoveFromLL(LL List, LLE e);
int RemoveFromLLByKey(LL List, char *key);
LLE GetNextLLE(LL List);
void ResetLLPosition(LL List);
void FreeLLE(LLE e, void (*free_e)(void *));
void FreeLL(LL List);


/* Internal */

#endif // _LL_H

--- NEW FILE: BUGS ---
- If you are in permitsome or denysome mdoe and remove someone from either
  your permit or deny list, the changes do not take effect until you
  resigon on. 

--- NEW FILE: network.c ---
/*
 * gaim
 *
 * Copyright (C) 1998-1999, Mark Spencer <markster at marko.net>
 *
 * 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
 * 
 */


/* 
 * Modified by Nadeem Riaz (nads at bleh.org) (just rewrote the get_address function)
 * for use in libtoc
 */

#include <netdb.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/socket.h>
#include "toc.h"
#include "proxy.h"

int proxy_type = 0;
char proxy_host[256];
int proxy_port = 3128;
char *proxy_realhost = NULL;

unsigned int *get_address(char *hostname)
{
	struct hostent *hp;
	unsigned int *sin=NULL;
	if ((hp = proxy_gethostbyname(hostname))) {
		sin = (unsigned int *) malloc(sizeof(unsigned int));
		bcopy((char *)(*(hp->h_addr_list)),(char *)sin,sizeof(hp->h_addr_list));
	}
	return sin;
}


int connect_address(unsigned int addy, unsigned short port)
{
        int fd;
	struct sockaddr_in sin;

	sin.sin_addr.s_addr = addy;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	
	fd = socket(AF_INET, SOCK_STREAM, 0);
	
	if (fd > -1) {
		quad_addr=strdup(inet_ntoa(sin.sin_addr));
		if (proxy_connect(fd, (struct sockaddr *)&sin, sizeof(sin)) > -1) {
			return fd;
		}
	}
	return -1;
}


/*
 * Proxy stuff
 */

/* this code is borrowed from cvs 1.10 */
static int
proxy_recv_line (int sock, char **resultp)
{
    int c;
    char *result;
    size_t input_index = 0;
    size_t result_size = 80;

    result = (char *) malloc (result_size);

    while (1)
    {
	char ch;
	if (recv (sock, &ch, 1, 0) < 0)
	    fprintf (stderr, "recv() error from  proxy server\n");
	c = ch;

	if (c == EOF)
	{
	    free (result);

	    /* It's end of file.  */
	    fprintf(stderr, "end of file from  server\n");
	}

	if (c == '\012')
	    break;

	result[input_index++] = c;
	while (input_index + 1 >= result_size)
	{
	    result_size *= 2;
	    result = (char *) realloc (result, result_size);
	}
    }

    if (resultp)
	*resultp = result;

    /* Terminate it just for kicks, but we *can* deal with embedded NULs.  */
    result[input_index] = '\0';

    if (resultp == NULL)
	free (result);
    return input_index;
}


struct hostent *proxy_gethostbyname(char *host)
{
    
        if (proxy_type == PROXY_NONE)
                return (gethostbyname(host));

        if (proxy_realhost != NULL)
                free(proxy_realhost);

        /* we keep the real host name for the Connect command */
        proxy_realhost = (char *) strdup(host);
        
        return (gethostbyname(proxy_host));
    
}


int proxy_connect(int  sockfd, struct sockaddr *serv_addr, int
                  addrlen )
{
        struct sockaddr_in name;
        int ret;

        switch (proxy_type) {
        case PROXY_NONE:
                /* normal use */
                return (connect(sockfd,serv_addr,addrlen));
                break;
        case PROXY_HTTP:  /* Http proxy */
                /* do the  tunneling */
                /* step one : connect to  proxy */
                {
                        struct hostent *hostinfo;
                        unsigned short shortport = proxy_port;

                        memset (&name, 0, sizeof (name));
                        name.sin_family = AF_INET;
                        name.sin_port = htons (shortport);
                        hostinfo = gethostbyname (proxy_host);
                        if (hostinfo == NULL) {
                                fprintf (stderr, "Unknown host %s.\n", proxy_host);
                                return (-1);
                        }
                        name.sin_addr = *(struct in_addr *) hostinfo->h_addr;
                }
                toc_debug_printf("Trying to connect ...\n");
                if ((ret = connect(sockfd,(struct sockaddr *)&name,sizeof(name)))<0)
                        return(ret);
    
                /* step two : do  proxy tunneling init */
                {
                        char cmd[80];
                        char *inputline;
                        unsigned short realport=ntohs(((struct sockaddr_in *)serv_addr)->sin_port);
                        sprintf(cmd,"CONNECT %s:%d HTTP/1.1\n\r\n\r",proxy_realhost,realport);
                        toc_debug_printf("<%s>\n",cmd);                    
                        if (send(sockfd,cmd,strlen(cmd),0)<0)
                                return(-1);
                        if (proxy_recv_line(sockfd,&inputline) < 0) {
                                return(-1);
                        }
                        toc_debug_printf("<%s>\n",inputline);
                        if (memcmp("HTTP/1.0 200 Connection established",inputline,35))
                                if (memcmp("HTTP/1.1 200 Connection established",inputline,35)) {
                                        free(inputline);
                                        return(-1);
                                }

                        while (strlen(inputline)>1) {
                                free(inputline);
                                if (proxy_recv_line(sockfd,&inputline) < 0) {
                                        return(-1);
                                }
                                toc_debug_printf("<%s>\n",inputline);
                        }
                        free(inputline);
                }
	        
                return ret;
                break;
        case PROXY_SOCKS:
                fprintf(stderr,"Socks proxy is not yet implemented.\n");
                return(-1);
                break;
        default:
                fprintf(stderr,"Unknown proxy type : %d.\n",proxy_type);
                break;
        }
        return(-1);
}



--- NEW FILE: util.c ---
/*
 * gaim
 *
 * Copyright (C) 1998-1999, Mark Spencer <markster at marko.net>
 *
 * 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
 * 
 */


/* 
 * Modified by Nadeem Riaz (nads at bleh.org)
 * 
 * Slight changes to better incorporate into libtoc
 */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/wait.h>
#include "toc.h"

void set_state(int i)
{
        state = i;
}

int escape_text(char *msg)
{
	char *c, *cpy;
	int cnt=0;
	/* Assumes you have a buffer able to cary at least BUF_LEN * 2 bytes */
	if (strlen(msg) > BUF_LEN) {
		fprintf(stderr, "Warning:  truncating message to 2048 bytes\n");
		msg[2047]='\0';
	}
	
	cpy = strdup(msg);
	c = cpy;
	while(*c) {
		switch(*c) {
		case '{':
		case '}':
		case '\\':
		case '"':
			msg[cnt++]='\\';
			/* Fall through */
		default:
			msg[cnt++]=*c;
		}
		c++;
	}
	msg[cnt]='\0';
	free(cpy);
	return cnt;
}


int escape_message(char *msg)
{
	char *c, *cpy;
	int cnt=0;
	/* Assumes you have a buffer able to cary at least BUF_LEN * 2 bytes */
	if (strlen(msg) > BUF_LEN) {
		toc_debug_printf("Warning:  truncating message to 2048 bytes\n");
		msg[2047]='\0';
	}
	
	cpy = strdup(msg);
	c = cpy;
	while(*c) {
		switch(*c) {
		case '$':
		case '[':
		case ']':
		case '(':
		case ')':
		case '#':
			msg[cnt++]='\\';
			/* Fall through */
		default:
			msg[cnt++]=*c;
		}
		c++;
	}
	msg[cnt]='\0';
	free(cpy);
	return cnt;
}

char *normalize(char *s)
{
	static char buf[BUF_LEN];
        char *t, *u;
        int x=0;

        u = t = malloc(strlen(s) + 1);

        strcpy(t, s);
        strdown(t);
        
	while(*t) {
		if (*t != ' ') {
			buf[x] = *t;
			x++;
		}
		t++;
	}
        buf[x]='\0';
        free(u);
	return buf;
}

void strdown(char *s) { 
	while ( *s ) {
		if ( *s >= 65 && *s <= 90) 
			*s += 32;
		s++;
	}
}

void toc_debug_printf(char *fmt, ...)
{
#ifdef DEBUG_LIB_TOC
	FILE *fp;
        char data[MAX_OUTPUT_MSG_LEN];
        va_list ptr;	
	if ( ! (fp=fopen(TOC_DEBUG_LOG,"a")) ) {
		perror("ERROR couldn't open debug log file!@$\n");
	}	
        va_start(ptr, fmt);
        vsnprintf(data, MAX_OUTPUT_MSG_LEN - 1 , fmt, ptr);
        va_end(ptr);
	fprintf(fp,"%s\n",data);
	fflush(fp);
        fclose(fp);
        return;  
#endif
}

void toc_msg_printf(int type, char *fmt, ...) {
        char data[MAX_OUTPUT_MSG_LEN];
	char *args[1];
        va_list ptr;	
        va_start(ptr, fmt);
        vsnprintf(data, MAX_OUTPUT_MSG_LEN - 1 , fmt, ptr);
        va_end(ptr);
	args[0] = data;
	use_handler(TOC_HANDLE,type,args);
        return;  	
}

char * strip_html(char * text)
{
	int i, j;
	int visible = 1;
	char *text2 = malloc(strlen(text) + 1);
	
	strcpy(text2, text);
	for (i = 0, j = 0;text2[i]; i++)
	{
		if(text2[i]=='<')
		{	
			visible = 0;
			continue;
		}
		else if(text2[i]=='>')
		{
			visible = 1;
			continue;
		}
		if(visible)
		{
			text2[j++] = text2[i];
		}
	}
	text2[j] = '\0';
	return text2;
}


--- NEW FILE: server.c ---
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include "toc.h"

static time_t lastsent = 0;
time_t login_time = 0;
int my_evil;
int is_idle = 0;
int lag_ms = 0;
int time_to_idle = 600;
int is_away = 0;
static struct timeval lag_tv;

void serv_add_buddy(char *name)
{
	char buf[1024];
	snprintf(buf, sizeof(buf), "toc_add_buddy %s", normalize(name));
	sflap_send(buf, -1, TYPE_DATA);
}

void serv_remove_buddy(char *name)
{
	char buf[1024];
	snprintf(buf, sizeof(buf), "toc_remove_buddy %s", normalize(name));
	sflap_send(buf, -1, TYPE_DATA);
}

int serv_got_im(char *name, char *message, int away)
{
	/*
	struct conversation *cnv;
	int is_idle = -1;
	*/
	char *nname;

	nname = strdup(normalize(name));

	if (!strcasecmp(normalize(name), nname)) {
		if (!strcmp(message, LAGOMETER_STR)) {
			struct timeval tv;
                        int ms;

			gettimeofday(&tv, NULL);

			ms = 1000000 * (tv.tv_sec - lag_tv.tv_sec);

			ms += tv.tv_usec - lag_tv.tv_usec;
			
			lag_ms = ms;
			use_handler(TOC_HANDLE,TOC_LAG_UPDATE,NULL);
			
                        return -1;
		}

	}

	/*
        cnv = find_conversation(name);

        if (cnv == NULL)
                cnv = new_conversation(name);

        if (away)
                write_to_conv(cnv, message, WFLAG_AUTO | WFLAG_RECV);
        else
                write_to_conv(cnv, message, WFLAG_RECV);


        if (cnv->makesound && extrasounds)
                play_sound(RECEIVE);


        if (awaymessage != NULL) {
                time_t t;

                time(&t);


                if ((cnv == NULL) || (t - cnv->sent_away) < 120)
                        return;

                cnv->sent_away = t;

                if (is_idle)
                        is_idle = -1;


                serv_send_im(name, awaymessage->message, 1);

                if (is_idle == -1)
                        is_idle = 1;

                write_to_conv(cnv, awaymessage->message, WFLAG_SEND | WFLAG_AUTO);
        }
	*/
	toc_debug_printf("Received im from %s : %s\n",name,message);
	return 1;
}

void serv_finish_login()
{
        char *buf;
        
        buf = strdup(user_info);
        escape_text(buf);
        serv_set_info(buf);
	free(buf);

	use_handler(TOC_HANDLE,TOC_REINSTALL_TIMER,NULL);

        time(&login_time);
	serv_touch_idle();

        serv_add_buddy(aim_username);
        
	if (!registered)
	{
		/* show_register_dialog(); */
		save_prefs();
	}
}

void serv_add_buddies(LL buddies)
{
	char buf[MSG_LEN];
	LLE e;
        int n, num = 0;
	
        n = snprintf(buf, sizeof(buf), "toc_add_buddy");
        for ( TLL(buddies,e) ) {
                if (num == 20) {
                        sflap_send(buf, -1, TYPE_DATA);
                        n = snprintf(buf, sizeof(buf), "toc_add_buddy");
                        num = 0;
                }
                ++num;
                n += snprintf(buf + n, sizeof(buf) - n, " %s", normalize((char *)e->key));
        }
	sflap_send(buf, -1, TYPE_DATA);
}




void serv_got_update(char *name, int loggedin, int evil, time_t signon, time_t idle, int type)
{
        struct buddy *b;
        char *nname,**args;
                     
        b = find_buddy(name);

        nname = strdup(normalize(name));
        if (!strcasecmp(nname, normalize(aim_username))) {
		/* 
                correction_time = (int)(signon - login_time);
                update_all_buddies();
		*/
		my_evil = evil;
                if (!b)
                        return;
        }

        
        if (!b) {
                toc_debug_printf("Error, no such person\n");
                return;
        }

        /* This code will 'align' the name from the TOC */
        /* server with what's in our record.  We want to */
        /* store things how THEY want it... */
	/*
        if (strcmp(name, b->name)) {
                GList  *cnv = conversations;
                struct conversation *cv;

                char *who = g_malloc(80);

                strcpy(who, normalize(name));

                while(cnv) {
                        cv = (struct conversation *)cnv->data;
                        if (!strcasecmp(who, normalize(cv->name))) {
                                g_snprintf(cv->name, sizeof(cv->name), "%s", name);
                                if (find_log_info(name) || log_all_conv)
                                        g_snprintf(who, 63, LOG_CONVERSATION_TITLE, name);
                                else
                                        g_snprintf(who, 63, CONVERSATION_TITLE, name);
                                gtk_window_set_title(GTK_WINDOW(cv->window), who);
				*/
                                /* no free 'who', set_title needs it.
                                 */
				 /*
                                break;
                        }
                        cnv = cnv->next;
                }

                g_snprintf(b->name, sizeof(b->name), "%s", name); */
                /*gtk_label_set_text(GTK_LABEL(b->label), b->name);*/

                /* okay lets save the new config... */

        /* } */

        b->idle = idle;
        b->evil = evil;
        b->uc = type;
        
        b->signon = signon;

        if (loggedin) {
                if (!b->present) {
                        b->present = 1;
			args = (char **) malloc(sizeof(char *)*1);
			args[0] = strdup(b->name);
			use_handler(TOC_HANDLE,TOC_BUDDY_LOGGED_ON,args);
			free(args[0]); free(args);
                        /* do_pounce(b->name); */
                }
        } else {
		if ( b->present ) {
			args = (char **) malloc(sizeof(char *)*1);
			args[0] = strdup(b->name);
			use_handler(TOC_HANDLE,TOC_BUDDY_LOGGED_OFF,args);
			free(args[0]); free(args);
		}
                b->present = 0;
	}
	/*
        set_buddy(b);
	*/
}


void serv_send_im(char *name, char *message)
{
	char buf[MSG_LEN - 7];
        snprintf(buf, MSG_LEN - 8, "toc_send_im %s \"%s\"%s", normalize(name),
                   message, ((is_away) ? " auto" : ""));
	sflap_send(buf, strlen(buf), TYPE_DATA);

        if (!is_away && strcasecmp(message,LAGOMETER_STR) != 0)
                serv_touch_idle();
	
}

void serv_close()
{
	toc_close();
}

void serv_save_config()
{
	char *buf = malloc(BUF_LONG);
	char *buf2 = malloc(MSG_LEN);
	toc_build_config(buf, BUF_LONG / 2); 
	snprintf(buf2, MSG_LEN, "toc_set_config {%s}", buf);
        sflap_send(buf2, -1, TYPE_DATA);
	free(buf2);
	free(buf);	
}

void serv_warn(char *name, int anon)
{
	char *send = malloc(256);
	snprintf(send, 255, "toc_evil %s %s", name,
		   ((anon) ? "anon" : "norm"));
	sflap_send(send, -1, TYPE_DATA);
	free(send);
}

void serv_add_permit(char *name)
{
	char buf[1024];
	snprintf(buf, sizeof(buf), "toc_add_permit %s", normalize(name));
	sflap_send(buf, -1, TYPE_DATA);
}



void serv_add_deny(char *name)
{
	char buf[1024];
	snprintf(buf, sizeof(buf), "toc_add_deny %s", normalize(name));
	sflap_send(buf, -1, TYPE_DATA);
}



void serv_set_permit_deny()
{
	char buf[MSG_LEN];
	char type[30];
	int at;
	LLE t;
	LL l;
        /* FIXME!  We flash here. */
        if (permdeny == PERMIT_PERMITALL || permdeny == PERMIT_PERMITSOME) {
		strcpy(type,"toc_add_permit");
		l = permit;		
        } else {
		strcpy(type,"toc_add_deny");                
		l = deny;
		
        }
	sflap_send(type, -1, TYPE_DATA);

	if ( permdeny == PERMIT_DENYALL || permdeny == PERMIT_PERMITALL ) {
		if ( permdeny == PERMIT_DENYALL ) 
			strcpy(type,"toc_add_permit");
		else 
			strcpy(type,"toc_add_deny");
		sflap_send(type, -1, TYPE_DATA);
		return;
	}
		
	at = snprintf(buf, sizeof(buf), "%s",type);
	for ( TLL(l,t) ) {
                at += snprintf(&buf[at], sizeof(buf) - at, " %s", normalize(t->key));
	}
	buf[at] = 0;
	sflap_send(buf, -1, TYPE_DATA);

}

void serv_got_joined_chat(int id, char *name)
{
        struct buddy_chat *b;

        b = (struct buddy_chat *) malloc(sizeof(struct buddy_chat));
        b->ignored = CreateLL();
        b->in_room = CreateLL();
        b->id = id;
	b->init_chat = 0;
        snprintf(b->name, 80, "%s", name);
	
	AddToLL(buddy_chats,name,b);
}

void serv_got_chat_left(int id)
{
        LLE t;
        struct buddy_chat *b = NULL;

        for ( TLL(buddy_chats,t) ) {
                b = (struct buddy_chat *)t->data;
                if (id == b->id) {
                        break;
                        }
                b = NULL;
        }

        if (!b)
                return;
	
	RemoveFromLLByKey(buddy_chats,b->name);
	
	toc_debug_printf("leaking memory in serv_got_chat_left");
}

void serv_accept_chat(int i)
{
        char *buf = malloc(256);
        snprintf(buf, 255, "toc_chat_accept %d",  i);
        sflap_send(buf, -1, TYPE_DATA);
        free(buf);
}

void serv_join_chat(int exchange, char *name)
{
        char buf[BUF_LONG];
        snprintf(buf, sizeof(buf)/2, "toc_chat_join %d \"%s\"", exchange, name);
        sflap_send(buf, -1, TYPE_DATA);
}

void serv_chat_invite(int id, char *message, char *name)
{
        char buf[BUF_LONG];
        snprintf(buf, sizeof(buf)/2, "toc_chat_invite %d \"%s\" %s", id, message, normalize(name));
        sflap_send(buf, -1, TYPE_DATA);
}

void serv_chat_leave(int id)
{
        char *buf = malloc(256);
        snprintf(buf, 255, "toc_chat_leave %d",  id);
        sflap_send(buf, -1, TYPE_DATA);
        free(buf);
}

void serv_chat_whisper(int id, char *who, char *message)
{
        char buf2[MSG_LEN];
        snprintf(buf2, sizeof(buf2), "toc_chat_whisper %d %s \"%s\"", id, who, message);
        sflap_send(buf2, -1, TYPE_DATA);
}

void serv_chat_send(int id, char *message)
{
        char buf[MSG_LEN];
        snprintf(buf, sizeof(buf), "toc_chat_send %d \"%s\"",id, message);
        sflap_send(buf, -1, TYPE_DATA);
	serv_touch_idle();
}

void serv_chat_warn(int  id, char *user, int anon) {
	char send[256];
	snprintf(send, 255, "toc_chat_evil %d %s %s", id, user,  ((anon) ? "anon" : "norm"));
	sflap_send(send, -1, TYPE_DATA);
}


void serv_get_dir(char *name) {
        char buf[MSG_LEN];
        snprintf(buf, MSG_LEN, "toc_get_dir %s", normalize(name));
        sflap_send(buf, -1, TYPE_DATA);
}

void serv_set_dir(char *first, char *middle, char *last, char *maiden,
		  char *city, char *state, char *country, char *email, int web)
{
	char buf2[BUF_LEN], buf[BUF_LEN];
	/* sending email seems to mess this up? */
	snprintf(buf2, sizeof(buf2), "%s:%s:%s:%s:%s:%s:%s:%s", first,
		   middle, last, maiden, city, state, country,
		   (web == 1) ? "Y" : "");
	escape_text(buf2);
	snprintf(buf, sizeof(buf), "toc_set_dir %s", buf2);
	sflap_send(buf, -1, TYPE_DATA);
}

void serv_dir_search(char *first, char *middle, char *last, char *maiden,
		     char *city, char *state, char *country, char *email)
{
	char buf[BUF_LONG];
	snprintf(buf, sizeof(buf)/2, "toc_dir_search %s:%s:%s:%s:%s:%s:%s:%s", first, middle, last, maiden, city, state, country, email);
	toc_debug_printf("Searching for: %s,%s,%s,%s,%s,%s,%s\n", first, middle, last, maiden, city, state, country);
	sflap_send(buf, -1, TYPE_DATA);
}


void serv_get_info(char *name)
{
        char buf[MSG_LEN];
        snprintf(buf, MSG_LEN, "toc_get_info %s", normalize(name));
        sflap_send(buf, -1, TYPE_DATA);
}

void serv_set_info(char *info)
{
	char buf[MSG_LEN];
	snprintf(buf, sizeof(buf), "toc_set_info \"%s\n\"", info);
	sflap_send(buf, -1, TYPE_DATA);
}

void serv_touch_idle() {
	/* Are we idle?  If so, not anymore */
	if (is_idle > 0) {
		is_idle = 0;
                serv_set_idle(0);
		use_handler(TOC_HANDLE,TOC_WENT_IDLE,NULL);
        }
        time(&lastsent);
}

void serv_set_idle(int time)
{
	char buf[256];
	snprintf(buf, sizeof(buf), "toc_set_idle %d", time);
	sflap_send(buf, -1, TYPE_DATA);
}

int check_idle() {
	time_t t;

	time(&t);

	use_handler(TOC_HANDLE,TOC_REINSTALL_TIMER,NULL);	
        gettimeofday(&lag_tv, NULL);
	serv_send_im(aim_username, LAGOMETER_STR);

	/*
	if (report_idle != IDLE_GAIM)
                return TRUE;
	*/

	
	if (is_idle || is_away)
		return 1;

	toc_debug_printf("time_to_idle = %d, current idle = %d, t = %d, last_sent = %d",time_to_idle,(t - lastsent),t,lastsent);
	if ((t - lastsent) > time_to_idle) { /* 10 minutes! */
		serv_set_idle((int)t - lastsent);
		toc_debug_printf("went idle wieth time_to_idle = %d",time_to_idle);
		use_handler(TOC_HANDLE,TOC_WENT_IDLE,NULL);
		is_idle = 1;
        }

        
	return 1;

}

void serv_set_away(char *message) {
        char buf[MSG_LEN];
        if ( ! is_away && message ) {
		is_away = 1;
                snprintf(buf, MSG_LEN, "toc_set_away \"%s\"", message);
        } else {
		is_away = 0;
                snprintf(buf, MSG_LEN, "toc_set_away");
	}
	sflap_send(buf, -1, TYPE_DATA);
}

--- NEW FILE: proxy.h ---
#ifndef _PROXY_H
#define _PROXY_H

/* proxy types */
#define PROXY_NONE 0
#define PROXY_HTTP 1
#define PROXY_SOCKS 2		/* Not Implemented !! */


extern struct hostent * proxy_gethostbyname(char *host);
extern int proxy_connect(int  sockfd, struct sockaddr *serv_addr, int addrlen );

extern int proxy_type;
extern char proxy_host[256];
extern int proxy_port;
extern char *proxy_realhost;

#endif /* _PROXY_H */

--- NEW FILE: README ---
Most of this code is from gaim, I just hacked it up a bit to un gtkify it
and separated it from the interface code. Anyway, I plan to completely
seperate this from the interface code and release it so anyone can add a
aim client to whatever they like.


--- NEW FILE: out ---
toc.c: In function `toc_callback':
toc.c:525: parse error before `;'
toc.c:525: warning: statement with no effect
toc.c:525: parse error before `)'
toc.c:528: break statement not within loop or switch
toc.c:515: warning: unused variable `buddy'
toc.c:532: `b' undeclared (first use in this function)
toc.c:532: (Each undeclared identifier is reported only once
toc.c:532: for each function it appears in.)
toc.c:536: `in' undeclared (first use in this function)
toc.c:537: `buddy' undeclared (first use in this function)
toc.c: At top level:
toc.c:571: parse error before `else'
toc.c:575: parse error before `2'
toc.c:575: warning: type defaults to `int' in declaration of `use_handler'
toc.c:575: warning: data definition has no type or storage class
toc.c:576: warning: type defaults to `int' in declaration of `idc'
toc.c:576: warning: initialization makes integer from pointer without a cast
toc.c:576: initializer element is not constant
toc.c:576: warning: data definition has no type or storage class
toc.c:577: parse error before string constant
toc.c:577: warning: type defaults to `int' in declaration of `sscanf'
toc.c:577: warning: data definition has no type or storage class
toc.c:579: warning: type defaults to `int' in declaration of `serv_got_chat_left'
toc.c:579: warning: parameter names (without types) in function declaration
toc.c:579: conflicting types for `serv_got_chat_left'
toc.h:191: previous declaration of `serv_got_chat_left'
toc.c:579: warning: data definition has no type or storage class
toc.c:581: warning: type defaults to `int' in declaration of `numargs'
toc.c:581: warning: data definition has no type or storage class
toc.c:582: warning: type defaults to `int' in declaration of `args'
toc.c:582: warning: initialization makes integer from pointer without a cast
toc.c:582: initializer element is not constant
toc.c:582: warning: data definition has no type or storage class
toc.c:583: warning: type defaults to `int' in declaration of `args'
toc.c:583: conflicting types for `args'
toc.c:582: previous declaration of `args'
toc.c:583: warning: passing arg 1 of `strdup' makes pointer from integer without a cast
toc.c:583: invalid initializer
toc.c:583: warning: data definition has no type or storage class
toc.c:584: warning: type defaults to `int' in declaration of `args'
toc.c:584: conflicting types for `args'
toc.c:583: previous declaration of `args'
toc.c:584: invalid initializer
toc.c:584: warning: data definition has no type or storage class
toc.c:585: parse error before `1'
toc.c:585: warning: type defaults to `int' in declaration of `use_handler'
toc.c:585: warning: data definition has no type or storage class
toc.c:589: conflicting types for `idc'
toc.c:576: previous declaration of `idc'
toc.c:591: `b' used prior to declaration
toc.c:593: parse error before `2'
toc.c:593: warning: type defaults to `int' in declaration of `use_handler'
toc.c:593: warning: data definition has no type or storage class
toc.c:594: warning: type defaults to `int' in declaration of `idc'
toc.c:594: conflicting types for `idc'
toc.c:589: previous declaration of `idc'
toc.c:594: warning: initialization makes integer from pointer without a cast
toc.c:594: initializer element is not constant
toc.c:594: warning: data definition has no type or storage class
toc.c:595: parse error before string constant
toc.c:595: warning: type defaults to `int' in declaration of `sscanf'
toc.c:595: warning: data definition has no type or storage class
toc.c:596: warning: type defaults to `int' in declaration of `who'
toc.c:596: conflicting types for `who'
toc.c:590: previous declaration of `who'
toc.c:596: warning: initialization makes integer from pointer without a cast
toc.c:596: initializer element is not constant
toc.c:596: warning: data definition has no type or storage class
toc.c:597: warning: type defaults to `int' in declaration of `whisper'
toc.c:597: conflicting types for `whisper'
toc.c:590: previous declaration of `whisper'
toc.c:597: warning: initialization makes integer from pointer without a cast
toc.c:597: initializer element is not constant
toc.c:597: warning: data definition has no type or storage class
toc.c:598: warning: type defaults to `int' in declaration of `m'
toc.c:598: conflicting types for `m'
toc.c:589: previous declaration of `m'
toc.c:598: initializer element is not constant
toc.c:598: warning: data definition has no type or storage class
toc.c:599: parse error before `while'
toc.c:608: warning: type defaults to `int' in declaration of `b'
toc.c:608: conflicting types for `b'
toc.c:591: previous declaration of `b'
toc.c:608: warning: initialization makes integer from pointer without a cast
toc.c:608: initializer element is not constant
toc.c:608: warning: data definition has no type or storage class
toc.c:609: parse error before `if'
toc.c:611: parse error before string constant
toc.c:611: warning: type defaults to `int' in declaration of `strcpy'
toc.c:611: warning: data definition has no type or storage class
toc.c:614: parse error before `->'
toc.c:614: warning: type defaults to `int' in declaration of `strcpy'
toc.c:614: warning: data definition has no type or storage class
toc.c:616: warning: type defaults to `int' in declaration of `numargs'
toc.c:616: redefinition of `numargs'
toc.c:581: `numargs' previously defined here
toc.c:616: warning: data definition has no type or storage class
toc.c:617: warning: type defaults to `int' in declaration of `args'
toc.c:617: conflicting types for `args'
toc.c:584: previous declaration of `args'
toc.c:617: warning: initialization makes integer from pointer without a cast
toc.c:617: initializer element is not constant
toc.c:617: warning: data definition has no type or storage class
toc.c:618: warning: type defaults to `int' in declaration of `args'
toc.c:618: conflicting types for `args'
toc.c:617: previous declaration of `args'
toc.c:618: warning: passing arg 1 of `strdup' makes pointer from integer without a cast
toc.c:618: invalid initializer
toc.c:618: warning: data definition has no type or storage class
toc.c:619: warning: type defaults to `int' in declaration of `args'
toc.c:619: conflicting types for `args'
toc.c:618: previous declaration of `args'
toc.c:619: warning: passing arg 1 of `strdup' makes pointer from integer without a cast
toc.c:619: invalid initializer
toc.c:619: warning: data definition has no type or storage class
toc.c:620: warning: type defaults to `int' in declaration of `args'
toc.c:620: conflicting types for `args'
toc.c:619: previous declaration of `args'
toc.c:620: warning: passing arg 1 of `strdup' makes pointer from integer without a cast
toc.c:620: invalid initializer
toc.c:620: warning: data definition has no type or storage class
toc.c:621: warning: type defaults to `int' in declaration of `args'
toc.c:621: conflicting types for `args'
toc.c:620: previous declaration of `args'
toc.c:621: warning: passing arg 1 of `strdup' makes pointer from integer without a cast
toc.c:621: invalid initializer
toc.c:621: warning: data definition has no type or storage class
toc.c:623: warning: type defaults to `int' in declaration of `args'
toc.c:623: conflicting types for `args'
toc.c:621: previous declaration of `args'
toc.c:623: invalid initializer
toc.c:623: warning: data definition has no type or storage class
toc.c:624: warning: type defaults to `int' in declaration of `args'
toc.c:624: conflicting types for `args'
toc.c:623: previous declaration of `args'
toc.c:624: invalid initializer
toc.c:624: warning: data definition has no type or storage class
toc.c:625: parse error before `1'
toc.c:625: warning: type defaults to `int' in declaration of `use_handler'
toc.c:625: warning: data definition has no type or storage class
toc.c:628: conflicting types for `who'
toc.c:596: previous declaration of `who'
toc.c:629: conflicting types for `idc'
toc.c:594: previous declaration of `idc'
toc.c:632: parse error before `2'
toc.c:632: warning: type defaults to `int' in declaration of `use_handler'
toc.c:632: warning: data definition has no type or storage class
toc.c:633: warning: type defaults to `int' in declaration of `name'
toc.c:633: warning: initialization makes integer from pointer without a cast
toc.c:633: initializer element is not constant
toc.c:633: warning: data definition has no type or storage class
toc.c:634: warning: type defaults to `int' in declaration of `idc'
toc.c:634: conflicting types for `idc'
toc.c:629: previous declaration of `idc'
toc.c:634: warning: initialization makes integer from pointer without a cast
toc.c:634: initializer element is not constant
toc.c:634: warning: data definition has no type or storage class
toc.c:635: parse error before string constant
toc.c:635: warning: type defaults to `int' in declaration of `sscanf'
toc.c:635: warning: data definition has no type or storage class
toc.c:636: warning: type defaults to `int' in declaration of `who'
toc.c:636: conflicting types for `who'
toc.c:628: previous declaration of `who'
toc.c:636: warning: initialization makes integer from pointer without a cast
toc.c:636: initializer element is not constant
toc.c:636: warning: data definition has no type or storage class
toc.c:637: warning: type defaults to `int' in declaration of `message'
toc.c:637: conflicting types for `message'
toc.c:629: previous declaration of `message'
toc.c:637: warning: initialization makes integer from pointer without a cast
toc.c:637: initializer element is not constant
toc.c:637: warning: data definition has no type or storage class
toc.c:639: warning: type defaults to `int' in declaration of `pid'
toc.c:639: conflicting types for `pid'
toc.c:630: previous declaration of `pid'
toc.c:639: warning: initialization makes integer from pointer without a cast
toc.c:639: initializer element is not constant
toc.c:639: warning: data definition has no type or storage class
toc.c:640: warning: type defaults to `int' in declaration of `pid'
toc.c:640: conflicting types for `pid'
toc.c:639: previous declaration of `pid'
toc.c:640: warning: initialization makes pointer from integer without a cast
toc.c:640: initializer element is not constant
toc.c:640: warning: data definition has no type or storage class
toc.c:641: warning: type defaults to `int' in declaration of `AddToLL'
toc.c:641: warning: parameter names (without types) in function declaration
toc.c:641: warning: data definition has no type or storage class
toc.c:642: warning: type defaults to `int' in declaration of `numargs'
toc.c:642: redefinition of `numargs'
toc.c:616: `numargs' previously defined here
toc.c:642: warning: data definition has no type or storage class
toc.c:643: warning: type defaults to `int' in declaration of `args'
toc.c:643: conflicting types for `args'
toc.c:624: previous declaration of `args'
toc.c:643: warning: initialization makes integer from pointer without a cast
toc.c:643: initializer element is not constant
toc.c:643: warning: data definition has no type or storage class
toc.c:644: warning: type defaults to `int' in declaration of `args'
toc.c:644: conflicting types for `args'
toc.c:643: previous declaration of `args'
toc.c:644: warning: passing arg 1 of `strdup' makes pointer from integer without a cast
toc.c:644: invalid initializer
toc.c:644: warning: data definition has no type or storage class
toc.c:645: warning: type defaults to `int' in declaration of `args'
toc.c:645: conflicting types for `args'
toc.c:644: previous declaration of `args'
toc.c:645: warning: passing arg 1 of `strdup' makes pointer from integer without a cast
toc.c:645: invalid initializer
toc.c:645: warning: data definition has no type or storage class
toc.c:646: warning: type defaults to `int' in declaration of `args'
toc.c:646: conflicting types for `args'
toc.c:645: previous declaration of `args'
toc.c:646: warning: passing arg 1 of `strdup' makes pointer from integer without a cast
toc.c:646: invalid initializer
toc.c:646: warning: data definition has no type or storage class
toc.c:647: warning: type defaults to `int' in declaration of `args'
toc.c:647: conflicting types for `args'
toc.c:646: previous declaration of `args'
toc.c:647: warning: passing arg 1 of `strdup' makes pointer from integer without a cast
toc.c:647: invalid initializer
toc.c:647: warning: data definition has no type or storage class
toc.c:648: warning: type defaults to `int' in declaration of `args'
toc.c:648: conflicting types for `args'
toc.c:647: previous declaration of `args'
toc.c:648: invalid initializer
toc.c:648: warning: data definition has no type or storage class
toc.c:649: parse error before `1'
toc.c:649: warning: type defaults to `int' in declaration of `use_handler'
toc.c:649: warning: data definition has no type or storage class
toc.c:653: warning: type defaults to `int' in declaration of `free'
toc.c:653: warning: parameter names (without types) in function declaration
toc.c:653: conflicting types for `free'
/usr/include/stdlib.h:484: previous declaration of `free'
toc.c:653: warning: data definition has no type or storage class
toc.c:654: warning: type defaults to `int' in declaration of `free'
toc.c:654: warning: parameter names (without types) in function declaration
toc.c:654: warning: data definition has no type or storage class
toc.c:655: parse error before `if'
toc.c:664: warning: type defaults to `int' in declaration of `free'
toc.c:664: warning: parameter names (without types) in function declaration
toc.c:664: warning: data definition has no type or storage class
toc.c:665: parse error before `}'
make: *** [toc.o] Error 1

--- NEW FILE: TODO ---
- fix BUGS
- code cleanup
- create better docummentation on usage

--- NEW FILE: interface.c ---
/*
 * interface.c
 *
 * by Nadeem Riaz (nads at bleh.org)
 *
 * Probably should be renamed misc.c (oh well)
 */

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "toc.h"

int (*TOC_RAW_HANDLERS[30])(int, char *); 
int (*TOC_HANDLERS[30])(int, char **);

void init_toc() {
	int x;
	groups = NULL;
	permit = NULL;
	deny = NULL;
	buddy_chats = NULL;
	invited_chats = NULL;
	strcpy(aim_host,TOC_HOST);
	aim_port = TOC_PORT;
	strcpy(login_host,AUTH_HOST);
	login_port = AUTH_PORT;

	/* Init Handlers */
	for (x=0;x<30;x++) 		
		TOC_HANDLERS[x] = NULL;
	for (x=0;x<30;x++) 
		TOC_RAW_HANDLERS[x] = NULL;
	
}

void init_lists() {
	if ( groups == NULL ) {
		groups = (LL) CreateLL();
		SetFreeLLE(groups,&misc_free_group);
	}
	if ( permit == NULL )
		permit = (LL) CreateLL();
	if ( deny == NULL )
		deny = (LL) CreateLL();
	if ( buddy_chats == NULL ) {
		buddy_chats = CreateLL();
		SetFreeLLE(buddy_chats,&misc_free_buddy_chat);
	}
	if ( invited_chats == NULL ) {
		invited_chats = CreateLL();
		SetFreeLLE(invited_chats,&misc_free_invited_chats);
	}
}


int install_handler(int type, int (*func)(int, char **)) {
	TOC_HANDLERS[type] = func;
	return 1;
}

int install_raw_handler(int type, int (*func)(int, char *)) {
	TOC_RAW_HANDLERS[type] = func; 
	return 1;
}


int use_handler(int mode,int type, void *args) {
	int ret = 0;
	toc_debug_printf("use_handler: mode = %d type = %d",mode,type);
	if ( mode == TOC_HANDLE ) {
		if ( TOC_HANDLERS[type] == NULL ) 
			toc_debug_printf("Error, no handler installed for %d type",type);
		else 
			ret = TOC_HANDLERS[type](type, (char **) args);
	} else if ( mode == TOC_RAW_HANDLE ) {
		if ( TOC_RAW_HANDLERS[type] == NULL ) 
			toc_debug_printf("Error, no raw handler installed for %d type",type);
		else 
			ret = TOC_RAW_HANDLERS[type](type, (char *) args);	
	} else {
		toc_debug_printf("Error: %d : unkown handle mode!",mode);
		ret = -1;
	} 
	return ret;
}




More information about the dslinux-commit mailing list