|
From: Bill S. <we...@ri...> - 2000-12-14 06:09:31
|
* ICQLIB 'icq_Event' Proposal
The main goal of this proposed interface is to provide a more
object-oriented approach to sending and receiving ICQ 'events', by:
1) reducing the number of callback functions that the library client must
install to receive events by consolidating them into a single
icq_EventReceived callback
2) provide a single entry point to send events, along with supporting
event structures (one structure for each event).
3) Make the asynchronous event status messages, currently passed through
icq_RequestNotify, consistent across all event types and transports (UDP
and TCP). I think the UDP code is good here, though I haven't taken a
thorough look lately, but I know my TCP code needs work, the file and
chat requests in particular.
* Event interface
There will be three main functions here:
1) all current receive event callbacks compressed into one:
void (*icq_EventReceived)(ICQLINK *link, icq_Event *event);
2) sending events would be through single call
long icq_SendEvent(ICQLINK *link, icq_Event *event, transport);
transport - ICQ_SEND_THRUSERVER, ICQ_SEND_DIRECT, ICQ_SEND_BESTWAY
returns a (long) event_id back to the program, used to match
events to the asynchronous event status notifications from
icq_EventNotify
3) asynchronous event status like sent, acked, failed, etc:
void (*icq_EventNotify)(ICQLINK *link, DWORD event_id, int result,
unsigned int length, void *data);
* icq_EventReceived
Some example code:
MainWindow::OnEventReceived(ICQLINK *link, icq_Event *event) {
switch(event->type) {
case ICQ_MESSAGE_EVENT:
MessageReceived((icq_MessageEvent *)event);
case ICQ_URL_EVENT:
MessageReceived((icq_URLEvent *)event);
default:
printf("message received from %d with unknown type!\n",
event->uin);
}
icq_EventDelete(event);
}
Fairly straightforward. Program receives messages and passes them along
based on their type.
* icq_SendEvent
Some example code:
// send someone a message
icq_MessageEvent *pevent = icq_InitMessageEvent();
(icq_Event *)pevent->uin = destination_uin;
pevent->message = message;
icq_SendEvent(icqlink, pevent, ICQ_SEND_BESTWAY);
// send a url through the server
icq_URLEvent *pevent = icq_InitURLEvent();
(icq Event *)pevent->uin = destination_uin;
pevent->message = message;
pevent->url = url;
icq_SendEvent(icqlink, pevent, ICQ_SEND_THRUSERVER);
This is definitely a little more work, but if you think about the
client's implementation, they could use the icq_Event structure right
away and it would probably actually SAVE code. ex. kicq could keep an
icq_Event member in its message class, and use the variables in the
directly instead of having class member variables in its classes.
I don't like the casting but I don't know how else to do struct
'inheritance' in c? Any better way? See the end of this proposal for my
structures...
I'm also tossing around the idea of leaving the old methods in for
convenience. So someone could still use icq_SendMessage(icqlink, uin,
message) for instance. It will be up to the coder to decide which
interface to use - the functional interface will probably work better for
quick and dirty programs and scripts, while the event structure would
probably work better for larger, object-oriented applications because
they can use them directly.
* icq_EventNotify
/* The request has been completed successfully. */
#define ICQ_NOTIFY_SUCCESS 0
/* The request has failed */
#define ICQ_NOTIFY_FAILED 1
/* A direct connection has been initiated to remote user */
#define ICQ_NOTIFY_CONNECTING 2
/* A direct connection has been established to remote user */
#define ICQ_NOTIFY_CONNECTED 3
/* A packet has been transmitted. Note in the case of UDP, this may
* be sent back by library more than once due to packet loss! */
#define ICQ_NOTIFY_SENT 4
/* The remote side has acknowledged the packet we sent */
#define ICQ_NOTIFY_ACK 5
TODO: add notification constants for proxy connecting, if used, e.g.
ICQ_NOTIFY_PROXY_CONNECTING, ICQ_NOTIFY_PROXY_CONNECTED,
ICQ_NOTIFY_PROXY_INITIALIZED, etc...
A few example timelines:
client: icq_SendEvent(icqlink, login_event, ICQ_SEND_BESTWAY)==1;
library: 1 ICQ_NOTIFY_SENT
... (time goes by while waiting for ack)
1 ICQ_NOTIFY_ACK - once received from the server
1 ICQ_NOTIFY_SUCCESS - this event has been transmitted
successfully
* NOTE: ICQ_NOTIFY_SUCCESS doesn't mean the LOGIN proceduce completed
successfully, only that the request was transmitted successfully.
You must wait for the ICQ_EVENT_LOGIN_SUCCESS event to be received from the
server.
client: icq_SendEvent(icqlink, message_event, ICQ_SEND_BESTWAY)==2;
library: 2 ICQ_NOTIFY_CONNECTING
... (delay during connect)
2 ICQ_NOTIFY_CONNECTED
2 ICQ_NOTIFY_SENT
... (delay waiting for ack)
2 ICQ_NOTIFY_ACK
2 ICQ_NOTIFY_SUCCESS
client: icq_SendEvent(icqlink, message_event, ICQ_SEND_THRUSERVER)==3;
library: 3 ICQ_NOTIFY_SENT
... (packet lost, server never acks)
3 ICQ_NOTIFY_SENT
...
3 ICQ_NOTIFY_ACK
3 ICQ_NOTIFY_SUCCESS
client: icq_SendEvent(icqlink, search_event, ICQ_SEND_BESTWAY)==4;
library: 4 ICQ_NOTIFY_SENT
...
4 ICQ_NOTIFY_ACK
4 ICQ_NOTIFY_SUCCESS
... icq_UserFoundEvents come in on icq_EventReceived for a while
... icq_SearchDoneEvents comes in
* old callbacks -> new events and some example structures
// icq_Logged - ICQ_EVENT_LOGIN_SUCCESS
// icq_Disconnected - ICQ_EVENT_DISCONNECTED
// icq_RecvMessage - ICQ_EVENT_MESSAGE
typedef struct icq_MessageEvent_s {
struct icq_Event header;
const char *message;
} icq_MessageEvent;
// icq_RecvURL - ICQ_EVENT_URL
typedef struct icq_URLEvent_s {
struct icq_Event header;
const char *message;
const char *url;
} icq_MessageEvent;
// icq_RecvWebPager - ICQ_EVENT_WEBPAGER
typedef struct icq_WebPagerEvent_s {
struct icq_Event header;
const char *nick;
const char *email;
const char *message;
} icq_WebPagerEvent;
// icq_RecvMailExpress - ICQ_EVENT_MAIL_EXPRESS
typedef struct icq_MailExpressEvent_s {
struct icq_Event header;
const char *nick;
const char *email;
const char *message;
} icq_MailExpressEvent;
// icq_RecvChatReq - ICQ_EVENT_CHAT_REQUEST
typedef struct icq_ChatRequestEvent_s {
struct icq_Event header;
const char *message;
} icq_ChatRequestEvent;
// icq_RecvFileReq - ICQ_EVENT_FILE_REQUEST
typedef struct icq_FileRequestEvent_s {
struct icq_Event header;
const char *message;
const char *filename;
unsigned long filesize;
} icq_FileRequestEvent;
// icq_RecvAdded - ICQ_EVENT_ADDED
typedef struct icq_AddedEvent_s {
struct icq_Event header;
const char *nick;
const char *first_name;
const char *last_name;
const Char *email;
} icq_AddedEvent;
// icq_RecvAuthReq - ICQ_EVENT_AUTHORIZE_REQUEST
typedef struct icq_AuthorizeRequestEvent_s {
struct icq_Event header;
const char *nick;
const char *first_name;
const char *last_name;
const char *email;
const char *message;
} icq_AuthorizeRequestEvent_s;
// icq_UserFound - ICQ_EVENT_USER_FOUND
typedef struct icq_UserFoundEvent_s {
struct icq_Event header;
unsigned long uin;
const char *nick;
const char *first_name;
const char *last_name;
const char *email;
char authorize_flag;
} icq_UserFoundEvent;
// icq_SearchDone - ICQ_EVENT_SEARCH_DONE
// icq_UserOnline - ICQ_EVENT_USER_ONLINE
typedef struct icq_UserOnlineEvent_s {
struct icq_Event header;
unsigned long status;
unsigned long ip;
int port;
unsigned long real_ip;
char tcp_flag;
} icq_UserOnlineEvent;
// icq_UserOffilne - ICQ_EVENT_USER_OFFLINE
// icq_InfoReply - ICQ_EVENT_INFO_REPLY
typedef struct icq_InfoReplyEvent_s {
unsigned long uin;
const char *nick;
const char *first_name;
const char *last_name;
const char *email;
char authorize_flag;
} icq_InfoReplyEvent;
// icq_ExtInfoReply - ICQ_EVENT_EXTENDED_INFO_REPLY
typedef struct icq_ExtendedInfoReply_s {
unsigned long uin;
int country_code;
char country_stat;
const char *city;
const char *state;
int age;
char gender;
const char *phone;
const char *hp; // ??
const char *about;
} icq_ExtendedInfoReply;
// icq_WrongPassword - ICQ_EVENT_INVALID_PASSWORD
// icq_InvalidUIN - ICQ_EVENT_INVALID_UIN
// icq_SrvAck - this would be passed back through icq_RequestNotify
|