1 /*
2 * SMAPI; Modified Squish MSGAPI
3 *
4 * Squish MSGAPI0 is copyright 1991 by Scott J. Dudley. All rights reserved.
5 * Modifications released to the public domain.
6 *
7 * Use of this file is subject to the restrictions contain in the Squish
8 * MSGAPI0 licence agreement. Please refer to licence.txt for complete
9 * details of the licencing restrictions. If you do not find the text
10 * of this agreement in licence.txt, or if you do not have this file,
11 * you should contact Scott Dudley at FidoNet node 1:249/106 or Internet
12 * e-mail Scott.Dudley@f106.n249.z1.fidonet.org.
13 *
14 * In no event should you proceed to use any of the source files in this
15 * archive without having accepted the terms of the MSGAPI0 licensing
16 * agreement, or such other agreement as you are able to reach with the
17 * author.
18 */
19
20 #include <string.h>
21 #include <stdlib.h>
22
23 #include <huskylib/compiler.h>
24
25
26 #ifdef HAS_SIGNAL_H
27 #include <signal.h>
28 #endif
29
30 #include <huskylib/huskylib.h>
31
32 /* Swith for build DLL */
33 #define DLLEXPORT
34 #include <huskylib/huskyext.h>
35
36 #include "msgapi.h"
37 #include "apidebug.h"
38
39 unsigned _SquishCloseOpenAreas(void);
40 void _SquishInit();
41 void _SquishDeInit();
42
43
44 static byte *intl = (byte *) "INTL";
45 static byte *fmpt = (byte *) "FMPT";
46 static byte *topt = (byte *) "TOPT";
47 static byte *area_colon = (byte *) "AREA:";
48
49 /*static char *copyright = "MSGAPI - Copyright 1991 by Scott J. Dudley. All rights reserved.";*/
50
51 /* Global error value for message API routines */
52
53 word _stdc msgapierr = 0;
54
55 struct _minf _stdc mi;
56
smapi_cvs_date()57 const char * _XPENTRY smapi_cvs_date(){
58 static
59 #include "../cvsdate.h"
60 return cvs_date;
61 }
62
_MsgCloseApi(void)63 int _MsgCloseApi(void)
64 {
65 int result = 0;
66 /*
67 TODO: DeInit (close open areas etc.) for all msgbase types
68 */
69
70 _SquishDeInit();
71 result = JamCloseOpenAreas();
72
73 return result;
74 }
75
76 #ifdef HAS_SIGNAL_H /* old: #ifdef __UNIX__ */
77 /* Just a dummy alarm-fnct */
alrm(int x)78 static void alrm(int x)
79 { unused(x); }
80 #endif
81
MsgOpenApi(struct _minf * minf)82 sword _XPENTRY MsgOpenApi(struct _minf *minf)
83 {
84 #ifdef HAS_SIGNAL_H /* old: #ifdef __UNIX__ */
85 struct sigaction alrmact;
86 #endif
87
88 /* unused(copyright);*/
89 mi.req_version = minf->req_version;
90 mi.def_zone = minf->def_zone;
91 mi.haveshare = minf->haveshare = shareloaded();
92
93 /* Version 2 Requested */
94 if (mi.req_version > 1 && mi.req_version < 50)
95 {
96 mi.smapi_version = minf->smapi_version = MSGAPI_VERSION;
97 mi.smapi_subversion = minf->smapi_subversion = MSGAPI_SUBVERSION;
98 }
99
100 _SquishInit();
101
102 atexit((void (*)(void))_MsgCloseApi);
103
104 /*
105 * Set the dummy alarm-fcnt to supress stupid messages.
106 */
107 #ifdef HAS_SIGNAL_H /* old: #ifdef __UNIX__ */
108 memset(&alrmact, 0, sizeof(alrmact));
109 alrmact.sa_handler = alrm;
110 sigaction(SIGALRM, &alrmact, 0);
111 #endif
112
113 return 0;
114 }
115
MsgCloseApi(void)116 sword _XPENTRY MsgCloseApi(void)
117 {
118 return (sword) _MsgCloseApi();
119 }
120
MsgOpenArea(byte * name,word mode,word type)121 MSGA *_XPENTRY MsgOpenArea(byte * name, word mode, word type)
122 {
123 switch( type & MSGTYPE_STORAGES ){
124 case MSGTYPE_SQUISH: return SquishOpenArea(name, mode, type);
125 case MSGTYPE_JAM: return JamOpenArea(name, mode, type);
126 case MSGTYPE_SDM: return SdmOpenArea(name, mode, type);
127 case MSGTYPE_PASSTHROUGH: msgapierr=MERR_NONE; /* Try to open pssthrough area */
128 return NULL;
129 default: msgapierr=MERR_BADA; /* illegal msgbase type */
130 return NULL;
131 }
132 }
133
MsgDeleteBase(char * name,word type)134 int MsgDeleteBase(char * name, word type)
135 {
136 if(!name) return FALSE;
137 switch( type & MSGTYPE_STORAGES ){
138 case MSGTYPE_SQUISH: return SquishDeleteBase(name);
139 case MSGTYPE_JAM: return JamDeleteBase(name);
140 case MSGTYPE_SDM: return SdmDeleteBase(name);
141 default: return TRUE;
142 }
143 }
144
MsgValidate(word type,byte * name)145 sword _XPENTRY MsgValidate(word type, byte * name)
146 {
147 switch( type & MSGTYPE_STORAGES ){
148 case MSGTYPE_SQUISH: return SquishValidate(name);
149 case MSGTYPE_JAM: return JamValidate(name);
150 case MSGTYPE_SDM: return SdmValidate(name);
151 default: return TRUE;
152 }
153 }
154
155 /*
156 * Check to see if a message handle is valid. This function should work
157 * for ALL handlers tied into MsgAPI. This also checks to make sure that
158 * the area which the message is from is also valid (ie. the message handle
159 * isn't valid unless the area handle of that message is also valid).
160 */
161
InvalidMsgh(MSGH * msgh)162 sword MSGAPI InvalidMsgh(MSGH * msgh)
163 {
164 if (msgh == NULL || msgh->id != MSGH_ID || InvalidMh(msgh->sq))
165 {
166 msgapierr = MERR_BADH;
167 return TRUE;
168 }
169
170 return FALSE;
171 }
172
173 /* Check to ensure that a message area handle is valid. */
174
InvalidMh(MSGA * mh)175 sword MSGAPI InvalidMh(MSGA * mh)
176 {
177 if (mh == NULL || mh->id != MSGAPI_ID)
178 {
179 msgapierr = MERR_BADH;
180 return TRUE;
181 }
182
183 return FALSE;
184 }
185
186 /* Check to ensure that a message handle is valid. */
187
InvalidMsg(XMSG * msg)188 sword MSGAPI InvalidMsg(XMSG * msg)
189 {
190 if (msg == NULL)
191 {
192 msgapierr = MERR_BADA;
193 return TRUE;
194 }
195
196 return FALSE;
197 }
198
199
StripNasties(byte * str)200 byte *StripNasties(byte * str)
201 {
202 byte *p;
203
204 if(str)
205 {
206 p = str;
207 while (*p != '\0')
208 {
209 if (*p < ' ')
210 {
211 *p = ' ';
212 }
213 p++;
214 }
215 }
216 return str;
217 }
218
219 /* Copy the text itself to a buffer, or count its length if out==NULL */
220
_CopyToBuf(byte * p,byte * out,byte ** end)221 static dword near _CopyToBuf(byte * p, byte * out, byte ** end)
222 {
223 dword len = 0;
224 byte *p_text = p;
225
226 if (out)
227 {
228 *out++ = '\001';
229 }
230
231 len++;
232
233 while (*p == '\015' || *p == '\012')
234 {
235 p++;
236 }
237
238 while (*p == '\001' || strncmp((char *) p, (char *) area_colon, 5) == 0)
239 {
240 /* Skip over the first ^a */
241
242 if (*p == '\001')
243 {
244 p++;
245 }
246
247 while (*p && *p != '\015' && *p != '\012')
248 {
249 if (out)
250 {
251 *out++ = *p;
252 }
253
254 p++;
255 len++;
256 }
257
258 if (out)
259 {
260 *out++ = '\001';
261 }
262
263 len++;
264
265 /* preserve empty lines between kludges and text */
266 if (*p == '\015' || *p == '\012'){
267 if ((p[0] == '\015' && p[1] == '\012')||(p[0] == '\012' && p[1] == '\015'))
268 p_text = p+=2;
269 else
270 p_text = ++p;
271 }
272 while (*p == '\015' || *p == '\012')
273 {
274 p++;
275 }
276 }
277
278 /* Cap the string */
279
280 if (out)
281 {
282 *out = '\0';
283 }
284
285 len++;
286
287 /* Make sure to leave no trailing x01's. */
288
289 if (out && out[-1] == '\001')
290 {
291 out[-1] = '\0';
292 }
293
294 /* Now store the new end location of the kludge lines */
295
296 if (end)
297 {
298 *end = p_text;
299 }
300
301 return len;
302 }
303
CopyToControlBuf(byte * txt,byte ** newtext,unsigned * length)304 byte *_XPENTRY CopyToControlBuf(byte * txt, byte ** newtext, unsigned *length)
305 {
306 byte *cbuf, *end;
307
308 dword clen;
309
310 /* Figure out how long the control info is */
311
312 clen = _CopyToBuf(txt, NULL, NULL);
313
314 /* Allocate memory for it */
315
316 #define SAFE_CLEN 20
317
318 cbuf = palloc(clen + SAFE_CLEN);
319 if (cbuf == NULL)
320 {
321 return NULL;
322 }
323
324 memset(cbuf, '\0', clen + SAFE_CLEN);
325
326 /* Now copy the text itself */
327
328 clen = _CopyToBuf(txt, cbuf, &end);
329
330 if (length)
331 {
332 *length -= (size_t) (end - txt);
333 }
334
335 if (newtext)
336 {
337 *newtext = end;
338 }
339
340 return cbuf;
341 }
342
GetCtrlToken(byte * where,byte * what)343 byte *_XPENTRY GetCtrlToken(byte *where, byte *what)
344 {
345 byte *end, *out;
346 unsigned int len;
347
348 if (where == NULL || what == NULL) return NULL;
349 len = strlen((char *)what);
350
351 do {
352 where = (byte *)strchr((char *)where, '\001');
353 if (where == NULL) break;
354 where++;
355 } while (strncmp((char *)where, (char *)what, len));
356
357 if (where == NULL || strlen((char *)where)<len) return NULL;
358
359 end = (byte *) strchr((char *) where, '\r');
360 if (end == NULL) end = (byte *) strchr((char *) where, '\001');
361 if (end == NULL) end = where + strlen((char *) where);
362
363 out = palloc((size_t) (end - where) + 1);
364 if (out == NULL) return NULL;
365
366 memmove(out, where, (size_t) (end - where));
367 out[(size_t) (end - where)] = '\0';
368 return out;
369 }
370
371 /* NETADDR content is rewritten with discovered information */
372 /* If some address pieces aren't discovered then they stay intact */
373 /* Be sure these structures don't contain junk before this call */
ConvertControlInfo(byte * ctrl,NETADDR * orig,NETADDR * dest)374 void _XPENTRY ConvertControlInfo(byte * ctrl, NETADDR * orig, NETADDR * dest)
375 {
376 byte *s;
377 const char *p;
378
379 s = GetCtrlToken(ctrl, intl);
380
381 if (s != NULL)
382 {
383 NETADDR norig, ndest;
384
385 p = (char*)s;
386
387 /* Copy the defaults from the original address */
388
389 norig = *orig;
390 ndest = *dest;
391
392 /* Parse the destination part of the kludge */
393
394 parseFtnAddrZ(p + 5, &ndest, FTNADDR_GOOD, &p);
395
396 while (*p != ' ' && *p) /* TODO: Should'n be the case! Maybe remove it and skip intl processing. */
397 {
398 p++;
399 }
400
401 parseFtnAddrZS(p, &norig);
402
403 pfree(s);
404
405 /*
406 * Only use this as the "real" zonegate address if the net/node
407 * addresses in the INTL line match those in the message body.
408 * Otherwise, it's probably a gaterouted message!
409 */
410
411 if (ndest.net == dest->net && ndest.node == dest->node &&
412 norig.net == orig->net && norig.node == orig->node)
413 {
414 *dest = ndest;
415 *orig = norig;
416
417 /*
418 * Only remove the INTL line if it's not gaterouted, which is
419 * why we do it here.
420 */
421
422 /* mtt: DO NOT CHANGE THE MSGTEXT!!! */
423 /* RemoveFromCtrl(ctrl, intl); */
424 }
425 }
426
427 /* Handle the FMPT kludge */
428
429 s = GetCtrlToken(ctrl, fmpt);
430 if (s != NULL)
431 {
432 orig->point = (word) atoi((char *) s + 5);
433 pfree(s);
434 /* mtt: DO NO CHANGE THE MSGTEXT!!!! */
435 /* RemoveFromCtrl(ctrl, fmpt); */
436 }
437
438 /* Handle TOPT too */
439
440 s = GetCtrlToken(ctrl, topt);
441 if (s != NULL)
442 {
443 dest->point = (word) atoi((char *) s + 5);
444 pfree(s);
445 /* mtt: DO NOT CHANGE THE MSGTEXT!!! */
446 /* RemoveFromCtrl(ctrl, topt); */
447 }
448 }
449
CvtCtrlToKludge(byte * ctrl)450 byte *_XPENTRY CvtCtrlToKludge(byte * ctrl)
451 {
452 byte *from, *to, *buf;
453 size_t clen;
454
455 clen = strlen((char *) ctrl) + NumKludges((char *) ctrl) + 20;
456
457 buf = palloc(clen);
458 if (buf == NULL)
459 {
460 return NULL;
461 }
462
463 to = buf;
464
465 /* Convert ^aKLUDGE^aKLUDGE... into ^aKLUDGE\r^aKLUDGE\r... */
466
467 from = ctrl;
468 while (*from == '\001' && from[1])
469 {
470 /* Only copy out the ^a if it's NOT the area: line */
471
472 if (strncmp((char *) from + 1, (char *) area_colon, 5)!=0)
473 {
474 *to++ = *from;
475 }
476
477 from++;
478
479 while (*from && *from != '\001')
480 {
481 *to++ = *from++;
482 }
483
484 *to++ = '\r';
485 }
486
487 *to = '\0';
488
489 return buf;
490 }
491
RemoveFromCtrl(byte * ctrl,byte * what)492 void _XPENTRY RemoveFromCtrl(byte * ctrl, byte * what)
493 {
494 byte *p;
495 unsigned int len = strlen((char *)what);
496
497 for (;;)
498 {
499 ctrl = (unsigned char *)strchr((char *)ctrl, '\001');
500 if (ctrl == NULL) return;
501 if (strncmp((char *)ctrl+1, (char *)what, len)) {
502 ctrl++;
503 continue;
504 }
505 if (strlen((char *)ctrl + 1) < len) return;
506 /* found */
507 p = (unsigned char *)strchr((char *)ctrl + 1, '\001');
508 if (p == NULL) {
509 *ctrl = '\0';
510 return;
511 }
512 strocpy((char *)ctrl, (char *)p);
513 }
514 }
515
NumKludges(char * txt)516 word _XPENTRY NumKludges(char *txt)
517 {
518 word nk = 0;
519 char *p;
520
521 for(p=txt; ((p=strchr(p, '\001'))!=NULL); p++) nk++;
522
523 return nk;
524 }
525
526 /* Return MSGAPI error text (string constant).
527 */
strmerr(int msgapierr)528 char * _XPENTRY strmerr(int msgapierr)
529 {
530 switch (msgapierr) {
531 case MERR_NONE: return "No error";
532 case MERR_BADH: return "Invalid handle passed to function";
533 case MERR_BADF: return "Invalid or corrupted file";
534 case MERR_NOMEM: return "Not enough memory for specified operation";
535 case MERR_NODS: return "Maybe not enough disk space for operation";
536 case MERR_NOENT: return "File/message does not exist";
537 case MERR_BADA: return "Bad argument passed to msgapi function";
538 case MERR_EOPEN: return "Couldn't close - messages still open";
539 case MERR_NOLOCK: return "Base needs to be locked to perform operation";
540 case MERR_SHARE: return "Resource in use by other process";
541 case MERR_EACCES: return "Access denied (can't write to read-only, etc)";
542 case MERR_BADMSG: return "Bad message frame (Squish)";
543 case MERR_TOOBIG: return "Too much text/ctrlinfo to fit in frame (Squish)";
544 case MERR_BADNAME:return "Bad area name or file name";
545 case MERR_LIMIT: return "Messagebase limit is reached";
546 default: break;
547 }
548 return "Unknown error";
549 }
550
551
552 /* Check version of smapi library
553 * return zero if test failed; non-zero if passed
554 * test cvs need for DLL version only, using #include <smapi/cvsdate.h>
555 const char *smapidate(){
556 static const
557 #include "../smapi/smapi/cvsdate.h"
558 return cvs_date;
559 }
560 CheckSmapiVersion( ..., smapidate());
561 */
CheckSmapiVersion(int need_major,int need_minor,int need_patch,const char * cvs_date_string)562 int _XPENTRY CheckSmapiVersion( int need_major, int need_minor,
563 int need_patch, const char *cvs_date_string )
564 {
565 static
566 #include "../cvsdate.h" /* char cvs_date[]=datestring; */
567
568 if( need_major==MSGAPI_VERSION &&
569 need_minor==((MSGAPI_SUBVERSION & 0x0F0)>>4) &&
570 need_patch==(MSGAPI_SUBVERSION & 0x00F)
571 )
572 return !(cvs_date_string && strcmp(cvs_date_string,cvs_date));
573
574 return 0;
575 }
576