2 ** libCxClient - Citadel/UX Extensible Client API
3 ** Copyright (c) 2000, Flaming Sword Productions
4 ** Copyright (c) 2001, The Citadel/UX Consortium
9 ** Last Revision: 2000-11-16
10 ** Description: Miscellaneous support functions.
22 ** Function which we have hooked to.
24 static void (*_MiExpFunc)(const char*, const char*) = 0;
27 ** CxRevision(): Report revision information about libCxClient.
30 return(atof(VERSION));
34 ** CxSerialize(): Take a pipe-separated string & convert it into a 2-dimensional
35 ** array. THIS FUNCTION WILL HANDLE AN ABSOLUTE MAXIMUM OF 50 ARGUMENTS.
37 void CxSerialize(const char *s, char **Ser) {
38 char **ap, *argv[50], *end;
41 DPF((DFA,"Serializing '%s'",s));
43 for (ap = argv; (*ap = (char *)strsep((char **)&s, "|")) != NULL;) {
44 if (++ap >= &argv[50]) {
48 end = (char *)(ap - 1);
51 for(ap=&argv[0]; (char *)ap <= end; ap++) {
62 ** CxMiExpSend(): Send an express message. Think of this like AIM
66 ** (char *) user: Username
67 ** (char *) msg: Express message.
71 ** Failure; Unknown Error: 1
73 int CxMiExpSend(int id, const char *user, const char *msg) {
79 ** Need to check the server revision on this connection
80 ** handle. If the server only supports short-style
81 ** express messages, we're gonna have to implement it
82 ** that way (and strip out everything after the newline
83 ** in msg? or s/\n/ /g...?)
85 ** For reasons specified in session.txt, the following line
86 ** will never be guaranteed to work.. .
87 sprintf(xmit,"SEXP %s|%s",user, msg);
90 xmit = (char *)CxMalloc(strlen(user)+strlen(msg) + 7);
91 sprintf(xmit,"SEXP %s|-",user);
95 rc = CxClRecv( id, buf );
96 if( CHECKRC( rc, RC_SENDLIST ) ) {
97 DPF((DFA, "Sending:\n%s\n", msg));
99 DPF((DFA, "END STREAM.", msg));
100 CxClSend( id, "000" );
102 DPF((DFA,"Express Message accepted by server.")); /** we hope... **/
106 DPF((DFA,"Express Message _rejected_ by server."));
107 DPF((DFA,"(Operation not supported.)"));
113 ** CxMiExpRecv(): Receive an express message. Usually, this is
114 ** called after a NOOP loop returns RC_xxxx...
117 ** Success: Ptr to malloc()ed EXPRMESG struct. [*]
120 EXPRMESG *CxMiExpRecv( int id ) {
121 char buf[255], *Ser[20];
126 ** Ask the server for the latest Express Message [GEXP].
128 DPF((DFA,"Receive Express Message"));
129 CxClSend(id, "GEXP");
130 rc = CxClRecv(id, buf);
131 DPF((DFA,"buf=%s\n",buf));
135 ** If rc==RC_LISTING, then we have a valid Express Message.
137 DPF((DFA,"Checking result = ", rc));
138 if( CHECKRC(rc, RC_LISTING)) {
140 DPF((DFA,"This is an express message. Working on receiving..."));
141 toret = (EXPRMESG *) CxMalloc( sizeof(EXPRMESG) );
142 bzero( &toret, sizeof(EXPRMESG) );
144 CxSerialize( buf, (char **)&Ser );
146 toret->more_follows = atoi( Ser[0] );
147 toret->timestamp = (time_t) strtoul( Ser[1], 0, 10 );
148 toret->flags = atoi( Ser[2] );
149 strcpy( toret->sender, Ser[3] );
150 strcpy( toret->node, Ser[4] );
153 if((rc = CxClRecv(id, buf))) {
154 DPF((DFA, "toret->message @0x%08x", toret->message));
155 DPF((DFA, "+++ %s", buf));
157 toret->message = (char *) malloc(strlen(buf)+1);
159 toret->message = (char *) realloc(toret->message, strlen(toret->message)+strlen(buf)+1);
161 strcat(toret->message, buf);
165 /**** toret = (char *) CxMalloc(strlen(buf)+2);
169 if((rc = CxClRecv(id, buf))) {
171 toret = (char *) realloc(toret, strlen(toret)+strlen(buf)+1);
182 ** CxMiExpCheck(): Check to see if there are any EXPress MEssages
183 ** waiting for the currently logged-in user.
186 ** Message Waiting: 1
189 int CxMiExpCheck( int id ) {
193 DPF((DFA,"Sending NOOP"));
194 CxClSend(id, "NOOP");
195 DPF((DFA,"Checking response"));
196 rc = CxClRecv(id, buf);
199 ** CxClRecv() tacks on a RC_MESGWAIT flag to the result
200 ** code upon seeing a Message Waiting note from the
201 ** server. This behaviour is deprecated in updated
202 ** versions of Citadel/UX, but is still included for
203 ** compatibility's sake.
205 if(CHECKRC(rc,RC_MESGWAIT)) {
206 DPF((DFA,"Express Message waiting!"));
210 DPF((DFA,"No express message, loser."));
216 ** _CxMiExpHook(): Hook to RC_901 messages [Contain express messages]
217 ** [Not Intended For External Use]
220 void _CxMiExpHook(int id, const void* data) {
221 char buf[512], *user_buf, *data_buf;
224 DPF((DFA, "*ASYN* Received RC_901 message on CXID %d", id));
225 DPF((DFA, "Raw data: \"%s\"", (char *)data));
228 ** Fetch the sending user's information from the data stream.
230 rc = CxClRecv(id, buf);
231 user_buf = (char *)CxMalloc(strlen(buf)+1);
232 strcpy(user_buf, buf);
234 DPF(( DFA, "user_buf @0x%08x", data_buf ));
235 DPF(( DFA, "user_buf: %s", user_buf ));
237 DPF(( DFA, "allocating data_buf" ));
238 data_buf = (char *)CxMalloc(1);
240 DPF(( DFA, "allocated data_buf @0x%08x", data_buf ));
243 ** If this is a multi-line message, then fetch the message
244 ** from the datas stream.
246 if(CHECKRC(rc, RC_LISTING)) {
248 DPF(( DFA, "data_buf @0x%08x", data_buf ));
249 DPF(( DFA, "data_buf: %s", data_buf ));
250 rc = CxClRecv( id, buf );
252 DPF(( DFA, "data_buf szlen %d", strlen(data_buf) + strlen(buf) +1));
254 data_buf = realloc(data_buf, strlen(data_buf)+strlen(buf)+1);
255 strcat(data_buf, buf);
262 ** Pass this information off to the user's function.
264 DPF(( DFA, "Completed. Received the following data:\n: user_buf: %s\n: data_buf: %s\n",
265 user_buf, data_buf ));
267 DPF(( DFA, "->_MiExpFunc() -- USERLAND"));
268 _MiExpFunc(user_buf, data_buf);
269 DPF(( DFA, "<-_MiExpFunc() -- /USERLAND"));
271 DPF(( DFA, "Freeing pointer user_buf"));
273 DPF(( DFA, "Freeing pointer data_buf"));
276 DPF(( DFA, "Done!"));
280 ** CxMiExpHook(): We will allow the user to hook themselves into
281 ** our express message handler. Only one function is permitted to
285 ** func: The function that the user has written to handle Express
287 ** void func( const char *USER_FROM, const char *TEXT);
289 void CxMiExpHook(void (*func)(const char*, const char *)) {
291 DPF((DFA, "Hooking user func@0x%08x",func));
294 ** If libCxClient has not already hooked this type of
295 ** message, we need to go ahead and hook it to our
296 ** internal routing function.
298 if(!CxClCbExists(901)) {
299 DPF((DFA, "Hooking into RC_901"));
300 CxClCbRegister(901, _CxMiExpHook);
304 ** Now, register the user's hooked function with
305 ** ourselves. This instructs _CxMiExpHook() on
306 ** where to route data.
308 DPF((DFA,"Registering user hook"));
311 DPF((DFA,"Ok, at this point, RC_901 messages should be routed to the user."));
312 DPF((DFA,"Don't blame me if it doesn't work. You told me what to do, Brian."));
316 ** CxMiMessage(): Read a system message file, ONE LINE AT A TIME.
317 ** This function will return the current line sent by the server,
318 ** and will return NULL on completion. The caller is responsible
319 ** for freeing EACH LINE OF MEMORY passed to it.
322 ** (char *)file: The name of the file we want, or NULL to continue
323 ** the current stream...
326 ** Success: Ptr to malloc()ed file data. [*]
327 ** Failure; File not found: NULL
329 char *CxMiMessage(int id, const char *file) {
330 char buf[255], *toret;
333 if((file!=NULL) && file[0]) {
334 DPF((DFA,"Requesting %s from server.",file));
335 sprintf(buf,"MESG %s", file);
337 rc = CxClRecv(id, buf);
338 if(CHECKRC(rc, RC_LISTING)) {
339 DPF((DFA,"Retrieving line from file..."));
340 rc = CxClRecv(id, buf);
342 toret = (char *)CxMalloc(strlen(buf)+1);
344 DPF((DFA,"MEM/MDA:\t-1\t@0x%08x (Needs manual deallocation)", toret));
354 DPF((DFA,"Retrieving line from file..."));
355 rc = CxClRecv( id, buf);
357 toret = (char *)CxMalloc(strlen(buf)+1);
359 DPF((DFA,"MEM/MDA:\t-1\t@0x%08x (Needs manual deallocation)", toret));
367 ** Insurance measure...
373 ** CxMiImage(): Read a system image. Images are defined by the
374 ** Citadel/UX session protocol manual as always being in GIF
378 ** (char *)img: Name of the image we are requesting.
381 ** Success: Ptr to malloc()ed image data. [*]
382 ** Failure; File not found: NULL
384 ** (Actually, we will probably want to store this in a temp
385 ** file, and return a pointer to the filename. Unless you want
386 ** to store a 10-meg image in memory, of course... :)
388 char *CxMiImage(int id, const char *img) {
391 ** Hmm.. Not sure how similar this is to MESG...
392 ** Will defer this code until I can reference the