1 /*****************************************************************************/
2 /*                                                                           */
3 /*                 (C) Copyright 1996       Alberto Pasquale                 */
4 /*                 Portions (C) Copyright 1999 Per Lundberg                  */
5 /*                                                                           */
6 /*                   A L L   R I G H T S   R E S E R V E D                   */
7 /*                                                                           */
8 /*****************************************************************************/
9 /*                                                                           */
10 /*   How to contact the author:  Alberto Pasquale of 2:332/504@fidonet       */
11 /*                               Viale Verdi 106                             */
12 /*                               41100 Modena                                */
13 /*                               Italy                                       */
14 /*                                                                           */
15 /*****************************************************************************/
16 
17 #include "bbsgenlb.hpp"
18 #include <apgenlib.hpp>
19 #include <string.h>
20 #include <unistd.h>
21 
SqNetScan()22 SqNetScan::SqNetScan ()
23 {
24     harea = NULL;
25     hmsg = NULL;
26 }
27 
28 
~SqNetScan()29 SqNetScan::~SqNetScan ()
30 {
31     Close ();       // in the case it has not been done.
32 }
33 
34 
35   // try Open for 30 s
36 
MsgTOpenArea(byte * name,word mode,word type)37 static HAREA MsgTOpenArea (byte *name, word mode, word type)
38 {
39     int i = 0;
40 
41     HAREA ret = MsgOpenArea (name, mode, type);
42     while (!ret && (i < 30)) {
43         sleep (1);
44         i++;
45         ret = MsgOpenArea (name, mode, type);
46     };
47 
48     return ret;
49 }
50 
51 
52 // tryes MsgLock 6 times (30 s)
53 
54 
MsgTLock(HAREA ha)55 static sword MsgTLock (HAREA ha)
56 {
57     sword ret = 0;
58 
59     for (int i = 0; i < 6; i ++) {
60         ret = MsgLock (ha);
61         if (ret == 0)
62             break;
63     }
64 
65     return ret;
66 }
67 
68 
GetHwmID(const char * filename)69 static UMSGID GetHwmID (const char *filename)
70 {
71     UMSGID hwmID = 0;
72 
73     FILE *f = fopen (filename, "rb");
74     if (f) {
75         if (fread (&hwmID, sizeof (hwmID), 1, f) != 1)
76             hwmID = 0;
77         fclose (f);
78     }
79 
80     return hwmID;
81 }
82 
83 
SetHwmID(const char * filename,UMSGID hwmID)84 static int SetHwmID (const char *filename, UMSGID hwmID)
85 {
86     FILE *f = fopen (filename, "wb");
87     if (!f)
88         return -1;
89     int ret = 0;
90     ret |= (fwrite (&hwmID, sizeof (hwmID), 1, f) != 1);
91     ret |= fclose (f);
92 
93     return ret;
94 }
95 
96 
Open(const char * path,word type,word defzone,const char * sav)97 HAREA SqNetScan::Open (const char *path, word type, word defzone, const char *sav)
98 {
99     if (Close ())
100         return NULL;
101 
102     if ((type == MSGTYPE_SQUISH) && sav)
103         sprintf (savfilename, "%s.%s", path, sav);
104     else
105         savfilename[0] = '\0';
106 
107     areatype = type;
108     areazone = defzone;
109                                         // Area Open tries 30s
110 
111     harea = MsgTOpenArea ((byte *)path, MSGAREA_NORMAL, type);
112     if (!harea)
113         return NULL;
114 
115     if (MsgTLock (harea)) {      // MsgLock tries 30s
116        MsgCloseArea (harea);
117        harea = NULL;
118        return NULL;
119     }
120 
121     if (savfilename[0])
122         hwmID = GetHwmID (savfilename);
123     else
124         hwmID = 0;
125 
126     highID = MsgMsgnToUid (harea, MsgGetHighMsg (harea));
127 
128     if (highID < hwmID)   // if base has been rebuilt -> rescan
129         hwmID = 0;
130 
131     return harea;
132 }
133 
134 
135 
GetNextMsg(XMSG * xmsg,byte flags)136 UMSGID SqNetScan::GetNextMsg (XMSG *xmsg, byte flags)
137 {
138     if (!harea)
139         return 0;
140 
141     BOOL Found = FALSE;
142 
143     do {
144         if (hmsg) {
145             MsgCloseMsg (hmsg);
146             hmsg = NULL;
147         }
148 
149         UMSGID msgID = hwmID + 1;
150 
151         if (msgID > highID)
152             return 0;
153 
154         dword msgn = MsgUidToMsgn (harea, msgID, UID_NEXT);
155         if (msgn == 0)
156             return 0;
157         msgID = MsgMsgnToUid (harea, msgn);
158         if (msgID <= hwmID)  // not really necessary, but useful with new MSGAPI
159            return 0;         // if the final msg has been deleted in the meantime
160         if (msgID > highID)  // In the case highID has been deleted and we are
161             return 0;        // pointing to a newly created message.
162 
163         hmsg = MsgOpenMsg (harea, MOPEN_READ, msgn);
164         if (!hmsg)
165             return 0;
166 
167         dword readlen = MsgReadMsg (hmsg, xmsg, 0, 0, NULL, 0, NULL);
168         if (readlen == (dword)-1)
169             memset (xmsg, 0, sizeof (XMSG));    // in case of corrupted message
170         else {
171             if (xmsg->orig.zone == 0)           // default zone when necessary
172                 xmsg->orig.zone = areazone;
173             if (xmsg->dest.zone == 0)
174                 xmsg->dest.zone = areazone;
175         }
176 
177         hwmID = msgID;
178 
179         Found = TRUE;
180 
181         if ((flags & SQNS_Get_SkipRead) && (xmsg->attr & MSGREAD))
182             Found = FALSE;
183 
184     } while (!Found);
185 
186 
187     return hwmID;
188 }
189 
190 
LoadMsgBody(char * body,size_t size)191 void SqNetScan::LoadMsgBody (char *body, size_t size)
192 {
193     if (!hmsg)
194         return;
195     if (size < 1)
196         return;
197     dword readlen = MsgReadMsg (hmsg, NULL, 0, size-1, (byte *)body, 0, NULL);
198     if (readlen == (dword)-1)   // corrupted message !
199         body[0] = '\0';
200     else
201         body[(int)readlen] = '\0'; /* assure a NULL terminated string */
202 }
203 
204 
MarkMsgRead()205 int SqNetScan::MarkMsgRead ()
206 {
207     if (!hmsg)
208         return 1;
209     MsgCloseMsg (hmsg);
210                             // time critical if not locked
211 
212     hmsg = MsgOpenMsg (harea, MOPEN_RW, MsgUidToMsgn (harea, hwmID, UID_EXACT));
213     if (!hmsg)
214         return 1;
215 
216     int err = 0;
217 
218     XMSG xmsg;
219     // explicit typecast of -1 to unsigned to make smapi happy
220     // see smapi/sq_read.c
221     // IMHO this should be changed in smapi to sword
222     err |= (MsgReadMsg (hmsg, &xmsg, 0, 0, NULL, 0, NULL) == (dword)-1);
223     if (!err) {
224         xmsg.attr |= MSGREAD;
225         err |= (MsgWriteMsg (hmsg, 0, &xmsg, NULL, 0, 0, 0, NULL) == -1);
226     }
227     err |= MsgCloseMsg (hmsg);
228     hmsg = NULL;
229 
230     return err;
231 }
232 
233 
KillMsg()234 int SqNetScan::KillMsg ()
235 {
236     if (!hmsg)
237         return 1;
238     MsgCloseMsg (hmsg);
239     hmsg = NULL;
240 
241     if (MsgKillMsg (harea, MsgUidToMsgn (harea, hwmID, UID_EXACT)))
242         return 1;
243 
244     return 0;
245 }
246 
247 
Close()248 int SqNetScan::Close ()
249 {
250     if (hmsg) {
251         MsgCloseMsg (hmsg);
252         hmsg = NULL;
253     }
254 
255     int ret = 0;
256 
257     if (harea) {
258         if (savfilename[0])
259             if (SetHwmID (savfilename, hwmID))
260                 ret = 1;
261         MsgUnlock (harea);
262         if (MsgCloseArea (harea))
263             ret = -1;
264         harea = NULL;
265     }
266 
267     return ret;
268 }
269