]> code.citadel.org Git - citadel.git/blob - libCxClient/src/misc.c
Initial revision
[citadel.git] / libCxClient / src / misc.c
1 /**
2  ** libCxClient - Citadel/UX Extensible Client API
3  ** Copyright (c) 2000, Flaming Sword Productions
4  ** Copyright (c) 2001, The Citadel/UX Consortium
5  ** All Rights Reserved
6  **
7  ** Module: misc.o
8  ** Date: 2000-11-16
9  ** Last Revision: 2000-11-16
10  ** Description: Miscellaneous support functions.
11  ** CVS: $Id$
12  **/
13 #include        <stdio.h>
14 #include        <stdlib.h>
15 #include        <signal.h>
16 #include        <string.h>
17 #include        <CxClient.h>
18 #include        "autoconf.h"
19 #include        "uname.h"
20
21 /**
22  ** Function which we have hooked to.
23  **/
24 static void     (*_MiExpFunc)(const char*, const char*) = 0;
25
26 /**
27  ** CxRevision(): Report revision information about libCxClient.
28  **/
29 float           CxRevision() {
30         return(atof(VERSION));
31 }
32
33 /**
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.
36  **/
37 void            CxSerialize(const char *s, char **Ser) {
38 char            **ap, *argv[50], *end;
39 int             i;
40  
41         DPF((DFA,"Serializing '%s'",s));
42
43         for (ap = argv; (*ap = (char *)strsep(&s, "|")) != NULL;) {
44                 if (++ap >= &argv[50]) {
45                         break;
46                 }
47         }
48         end = (char *)(ap - 1);
49  
50         i = 0;
51         for(ap=&argv[0]; (char *)ap <= end; ap++) {
52                 Ser[i] = *ap;
53                 i++;
54         }
55
56         Ser[i] = 0;
57
58         DPF((DFA,"Done"));
59
60
61 /**
62  ** CxMiExpSend(): Send an express message.  Think of this like AIM
63  ** without AOL...
64  **
65  ** [Expects]
66  **  (char *) user: Username
67  **  (char *) msg: Express message.
68  **
69  ** [Returns]
70  **  Success: 0
71  **  Failure; Unknown Error: 1
72  **/
73 int             CxMiExpSend(const char *user, const char *msg) {
74 char            *xmit, buf[255];
75 int             rc;
76
77         DPF((DFA,"Send Express Message"));
78         xmit = (char *)CxMalloc(strlen(user)+strlen(msg) + 7);
79         sprintf(xmit,"SEXP %s|%s",user, msg);
80         CxClSend(xmit);
81         CxFree(xmit);
82
83         rc = CxClRecv(buf);
84         if( CHECKRC(rc, RC_OK) ) {
85                 return(0);
86
87         } else {
88                 return(1);
89         }
90 }
91
92 /**
93  ** CxMiExpRecv(): Receive an express message.  Usually, this is
94  ** called after a NOOP loop returns RC_xxxx...
95  **
96  ** [Returns]
97  **  Success: Ptr to malloc()ed message text.  [*]
98  **  Failure: NULL
99  **/
100 char            *CxMiExpRecv() {
101 char            buf[255], *toret;
102 int             rc;
103
104         DPF((DFA,"Receive Express Message"));
105         CxClSend("GEXP");
106         rc = CxClRecv(buf);
107         DPF((DFA,"buf=%s\n",buf));
108         toret = 0;
109         DPF((DFA,"Checking result = ", rc));
110         if( CHECKRC(rc, RC_LISTING)) {
111                 DPF((DFA,"Preparing to return"));
112                 toret = (char *) CxMalloc(strlen(buf)+2);
113                 strcpy(toret,buf);
114                 strcat(toret,"|");
115                 do {
116                         if((rc = CxClRecv(buf))) {
117                                 DPF((DFA,"%s",buf));
118                                 toret = (char *) realloc(toret, strlen(toret)+strlen(buf)+1);
119                                 strcat(toret,buf);
120                         }
121                 } while(rc<0);
122         }
123
124         DPF((DFA," toret = %s", toret));
125
126         return(toret);
127 }
128
129 /**
130  ** CxMiExpCheck(): Check to see if there are any EXPress MEssages
131  ** waiting for the currently logged-in user.
132  **
133  ** [Returns]
134  **  Message Waiting: 1
135  **  No Messages: 0
136  **/
137 int             CxMiExpCheck() {
138 int             rc;
139 char            buf[255];
140
141         DPF((DFA,"Sending NOOP"));
142         CxClSend("NOOP");
143         DPF((DFA,"Checking response"));
144         rc = CxClRecv(buf);
145
146         /**
147          ** CxClRecv() tacks on a RC_MESGWAIT flag to the result
148          ** code upon seeing a Message Waiting note from the
149          ** server.  This behaviour is deprecated in updated
150          ** versions of Citadel/UX, but is still included for
151          ** compatibility's sake.
152          **/
153         if(CHECKRC(rc,RC_MESGWAIT)) {
154                 DPF((DFA,"Express Message waiting!"));
155                 return(1);
156
157         } else {
158                 DPF((DFA,"No express message, loser."));
159                 return(0);
160         }
161 }
162
163 /**
164  ** _CxMiExpHook(): Hook to RC_901 messages [Contain express messages]
165  ** [Not Intended For External Use]
166  **/
167 static
168 void            _CxMiExpHook(const void* data) {
169 char            buf[512], *user_buf, *data_buf;
170 int             rc;
171
172         DPF((DFA, "Received RC_901 message"));
173         DPF((DFA, "Raw data: %s\n", (char *)data));
174
175         rc = CxClRecv(buf);
176         user_buf = (char *)CxMalloc(strlen(buf)+1);
177         strcpy(user_buf, buf);
178
179         data_buf = (char *)CxMalloc(1);
180         *(data_buf) = 0;
181
182         /**
183          ** If this is a multi-line message:
184          **/
185         if(CHECKRC(rc, RC_LISTING)) {
186                 do {
187                         rc = CxClRecv(buf);
188                         if(rc<0) {
189                                 realloc(data_buf, strlen(data_buf)+strlen(buf));
190                                 strcat(data_buf, buf);
191                         }
192                 } while(rc < 0);
193         }
194         _MiExpFunc(user_buf, data_buf);
195         CxFree(user_buf);
196         CxFree(data_buf);
197 }
198
199 /**
200  ** CxMiExpHook(): We will allow the user to hook themselves into
201  ** our express message handler.  Only one function is permitted to
202  ** hook here.
203  **
204  ** [Expects]
205  **  func: The function that the user has written to handle Express
206  **        Messages.  
207  **        void func( const char *USER_FROM, const char *TEXT);
208  **/
209 void            CxMiExpHook(void (*func)(const char*, const char *)) {
210
211         DPF((DFA, "Hooking user func@0x%08x",func));
212
213         /**
214          ** If libCxClient has not already hooked this type of
215          ** message, we need to go ahead and hook it to our
216          ** internal routing function.
217          **/
218         if(!CxClCbExists(901)) {
219                 DPF((DFA, "Hooking into RC_901"));
220                 CxClCbRegister(901, _CxMiExpHook);
221         }
222
223         /**
224          ** Now, register the user's hooked function with
225          ** ourselves.  This instructs _CxMiExpHook() on
226          ** where to route data.
227          **/
228         DPF((DFA,"Registering user hook"));
229         _MiExpFunc = func;
230
231         DPF((DFA,"Ok, at this point, RC_901 messages should be routed to the user."));   
232         DPF((DFA,"Don't blame me if it doesn't work.  You told me what to do, Brian."));
233 }
234
235 /**
236  ** CxMiMessage(): Read a system message file, ONE LINE AT A TIME.
237  ** This function will return the current line sent by the server,
238  ** and will return NULL on completion.  The caller is responsible
239  ** for freeing EACH LINE OF MEMORY passed to it.
240  **
241  ** [Expects]
242  **  (char *)file: The name of the file we want, or NULL to continue
243  **  the current stream...
244  **
245  ** [Returns]
246  **  Success: Ptr to malloc()ed file data.  [*]
247  **  Failure; File not found: NULL
248  **/
249 char            *CxMiMessage(const char *file) {
250 char            buf[255], *toret;
251 int             rc;
252
253         if((file!=NULL) && file[0]) {
254                 DPF((DFA,"Requesting %s from server.",file));
255                 sprintf(buf,"MESG %s", file);
256                 CxClSend(buf);
257                 rc = CxClRecv(buf);
258                 if(CHECKRC(rc, RC_LISTING)) {
259                         DPF((DFA,"Retrieving line from file..."));
260                         rc = CxClRecv(buf);
261                         if(rc < 0) {
262                                 toret = (char *)CxMalloc(strlen(buf)+1);
263                                 strcpy(toret, buf);
264                                 DPF((DFA,"MEM/MDA:\t-1\t@0x%08x (Needs manual deallocation)", toret)); 
265                                 return(toret);
266                         } else {
267                                 return(NULL);
268                         }
269                 } else {
270                         return(NULL);
271                 }
272         } else {
273
274                 DPF((DFA,"Retrieving line from file..."));
275                 rc = CxClRecv(buf);
276                 if(rc < 0) {
277                         toret = (char *)CxMalloc(strlen(buf)+1);
278                         strcpy(toret,buf);
279                         DPF((DFA,"MEM/MDA:\t-1\t@0x%08x (Needs manual deallocation)", toret)); 
280                         return(toret);
281                 } else {
282                         return(NULL);
283                 }
284         }
285
286         /**
287          ** Insurance measure...
288          **/
289         return(NULL);
290 }
291
292 /**
293  ** CxMiImage(): Read a system image.  Images are defined by the 
294  ** Citadel/UX session protocol manual as always being in GIF
295  ** format.  
296  **
297  ** [Expects]
298  **  (char *)img: Name of the image we are requesting.
299  **
300  ** [Returns]
301  **  Success: Ptr to malloc()ed image data.  [*]
302  **  Failure; File not found: NULL
303  **/
304 char            *CxMiImage(const char *img) {
305
306         /**
307          ** Hmm.. Not sure how similar this is to MESG...
308          ** Will defer this code until I can reference the 
309          ** specs..
310          **/
311
312         return(NULL);
313 }