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