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