1 /*****************************************************************************
2  * HPT --- FTN NetMail/EchoMail Tosser
3  *****************************************************************************
4  *
5  * hpt-to-libareafix interface by val khokhlov, 2:550/180@fidonet
6  *
7  * This file is part of HPT.
8  *
9  * HPT is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by the
11  * Free Software Foundation; either version 2, or (at your option) any
12  * later version.
13  *
14  * HPT is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with HPT; see the file COPYING.  If not, write to the Free
21  * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22  *****************************************************************************/
23 /* $Id$ */
24 
25 #include <string.h>
26 #include <huskylib/xstr.h>
27 #include <smapi/msgapi.h>
28 #include <fidoconf/fidoconf.h>
29 #include <fidoconf/common.h>
30 #include <fidoconf/afixcmd.h>
31 #include <areafix/areafix.h>
32 #include <areafix/afglobal.h>
33 #include <areafix/callback.h>
34 #include <areafix/query.h>
35 #include "global.h"
36 #include "fcommon.h"
37 #include "hpt.h"
38 #include "dupe.h"
39 #include "scanarea.h"
40 #include "toss.h"
41 #ifdef DO_PERL
42 #include "hptperl.h"
43 #endif
44 
45 extern s_message **msgToSysop;
46 
afGetArea(char * areaName)47 s_area *afGetArea(char *areaName) {
48     s_area *area = getArea(config, areaName);
49     return area != &(config->badArea) ? area : NULL;
50 }
51 
afIsValidConference(const char * s)52 int afIsValidConference(const char *s) {
53     if (!s || strlen(s) > 60) return BM_AREATAG_TOO_LONG;
54     /*  according to FSC-0074 with lowercase symbols */
55     /*  lowercase symbols only for internal use */
56     while (*s) {
57         if ( !(*s >= 33 && *s <= 126) ) return BM_ILLEGAL_CHARS;
58         s++;
59     }
60     return 0;
61 }
62 
afSendMsg(s_message * tmpmsg)63 int afSendMsg(s_message *tmpmsg) {
64         processNMMsg(tmpmsg, NULL, getRobotsArea(config), 0, MSGLOCAL);
65         writeEchoTossLogEntry(getRobotsArea(config)->areaName);
66         closeOpenedPkt();
67         freeMsgBuffers(tmpmsg);
68   return 1;
69 }
70 
afWriteMsgToSysop(s_message * msg)71 int afWriteMsgToSysop(s_message *msg) {
72   msgToSysop[0] = msg;
73   writeMsgToSysop();
74   freeMsgBuffers(msg);
75   msgToSysop[0] = NULL;
76   return 1;
77 }
78 
afReportAutoCreate(char * c_area,char * descr,hs_addr pktOrigAddr,ps_addr forwardAddr)79 void afReportAutoCreate(char *c_area, char *descr, hs_addr pktOrigAddr, ps_addr forwardAddr) {
80   unused(descr);
81 #if 0 /* val: don't know why is was here; so trying to fix */
82   if (forwardAddr == NULL) makeMsgToSysop(c_area, pktOrigAddr, NULL);
83   else makeMsgToSysop(c_area, *forwardAddr, &pktOrigAddr);
84 #else
85   makeMsgToSysop(c_area, pktOrigAddr, forwardAddr);
86 #endif
87 }
88 
afDeleteArea(s_link * link,s_area * area)89 int afDeleteArea(s_link *link, s_area *area) {
90 
91    unused(link);
92 
93    if (area->dupeCheck != dcOff && config->typeDupeBase != commonDupeBase) {
94      char *dupename = createDupeFileName(area);
95      if (dupename) {
96        unlink(dupename);
97        nfree(dupename);
98      }
99    }
100    return 1;
101 }
102 
afRescanArea(char ** report,s_link * link,s_area * area,long rescanCount,long rescanAfter)103 int afRescanArea(char **report, s_link *link, s_area *area, long rescanCount, long rescanAfter) {
104   char *an = area->areaName;
105   s_arealink *arealink;
106   long rcc = 0;
107 
108             arealink = getAreaLink(area, link->hisAka);
109 
110             if ((area->msgbType == MSGTYPE_PASSTHROUGH) || (!arealink->rescan)) {
111                 xscatprintf(report," %s %s  no rescan possible\r",
112                             an, print_ch(49-strlen(an), '.'));
113                 w_log(LL_AREAFIX, "areafix: %s area no rescan possible to %s",
114                       an, aka2str(link->hisAka));
115             } else {
116                 if (link->rescanLimit) {
117                   if (rescanCount < 0 || rescanCount > link->rescanLimit)
118                     rescanCount = link->rescanLimit;
119                 }
120                 if (arealink->aexport) {
121                     rcc = rescanEMArea(area, arealink, rescanCount, rescanAfter);
122                     tossTempOutbound(config->tempOutbound);
123                 } else {
124                     rcc = 0;
125                     xscatprintf(report," %s %s  no access to export\r",
126                                 an, print_ch(49-strlen(an), '.'));
127                     w_log(LL_AREAFIX, "areafix: %s -- no access to export for %s",
128                           an, aka2str(link->hisAka));
129                 }
130                 xscatprintf(report," %s %s  rescanned %lu mails\r",
131                             an, print_ch(49-strlen(an), '.'), rcc);
132                 w_log(LL_AREAFIX,"areafix: %s rescanned %lu mails to %s",
133                       an, rcc, aka2str(link->hisAka));
134             }
135   return rcc;
136 }
137 
getLinkRobot(s_link * link)138 s_link_robot *getLinkRobot(s_link *link) {
139     return &(link->areafix);
140 }
141 
autoPassive()142 void autoPassive()
143 {
144   time_t   time_cur, time_test;
145   struct   stat stat_file;
146   s_message *msg;
147   FILE *f;
148   char *line, *path;
149   unsigned int i, rc = 0;
150 
151   for (i = 0; i < config->linkCount; i++) {
152 
153       if (config->links[i]->autoPause==0 || (config->links[i]->Pause == (ECHOAREA|FILEAREA))
154          ) continue;
155 
156       if (createOutboundFileName(config->links[i],
157                                  config->links[i]->echoMailFlavour,
158                                  FLOFILE) == 0) {
159           f = fopen(config->links[i]->floFile, "rt");
160           if (f) {
161               while ((line = readLine(f)) != NULL) {
162                   line = trimLine(line);
163                   path = line;
164                   if (!isArcMail(path)) {
165                       nfree(line);
166                       continue;
167                   }
168                   if (*path && (*path == '^' || *path == '#')) {
169                       path++;
170                       /*  set Pause if files stored only in outbound */
171                       if (*path && strncmp(config->outbound,path,strlen(config->outbound)-1)==0 && stat(path, &stat_file) != -1) {
172 
173                           time_cur = time(NULL);
174                           if (time_cur > stat_file.st_mtime) {
175                               time_test = (time_cur - stat_file.st_mtime)/3600;
176                           } else { /*  buggly time on file, anyway don't autopause on it */
177                               time_test = 0;
178                           }
179 
180                           if (time_test >= (time_t)(config->links[i]->autoPause*24)) {
181                               w_log(LL_AREAFIX, "autopause: the file %s is %d days old", path, time_test/24);
182                               if (Changepause((cfgFile) ? cfgFile :
183                                               getConfigFileName(),
184                                               config->links[i], 1,
185                                               config->links[i]->Pause^(ECHOAREA|FILEAREA))) {
186                                   UINT j, k;
187                                   int mask = config->links[i]->areafix.reportsAttr ? config->links[i]->areafix.reportsAttr : robot->reportsAttr;
188                                   msg = makeMessage(config->links[i]->ourAka,
189                                             &(config->links[i]->hisAka),
190                                             robot->fromName ? robot->fromName : versionStr,
191                                             config->links[i]->name,
192                                             "AutoPassive", 1,
193                                             MSGPRIVATE | MSGLOCAL | (mask & (MSGKILL|MSGCPT)) );
194                                   msg->text = createKludges(config, NULL,
195                                             config->links[i]->ourAka,
196                                             &(config->links[i]->hisAka),
197                                             versionStr);
198                                   xstrcat(&msg->text, "\r System switched to passive, your subscription is paused.\r\r"
199                                         " You are being unsubscribed from echo areas with no downlinks besides you!\r\r"
200                                         " When you wish to continue receiving echomail, please send requests\r"
201                                         " to AreaFix containing the %RESUME command.");
202                                   xscatprintf(&msg->text, "\r\r--- %s autopause\r", versionStr);
203                                   msg->textLength = strlen(msg->text);
204 #ifdef DO_PERL
205                                   perl_robotmsg(msg, robot->name);
206 #endif
207                                   processNMMsg(msg, NULL, getRobotsArea(config), 0, MSGLOCAL);
208                                   writeEchoTossLogEntry(getRobotsArea(config)->areaName);
209                                   closeOpenedPkt();
210                                   freeMsgBuffers(msg);
211                                   nfree(msg);
212 
213                                   /* update arealink access */
214                                   for (k = 0; k < config->echoAreaCount; k++)
215                                       for (j = 0; j < config->echoAreas[k].downlinkCount; j++)
216                                           if (config->links[i] == config->echoAreas[k].downlinks[j]->link)
217                                           {
218                                               setLinkAccess(config, &(config->echoAreas[k]), config->echoAreas[k].downlinks[j]);
219                                               break;
220                                           }
221 
222                                   /* pause areas with one link alive while others are paused */
223                                   if (robot->autoAreaPause)
224                                       rc += pauseArea(ACT_PAUSE, config->links[i], NULL);
225 #ifdef DO_PERL
226                                   /* update perl vars */
227                                   perl_invalidate(PERL_CONF_LINKS|PERL_CONF_AREAS);
228 #endif
229                               } /*  end changepause */
230                               nfree(line);
231                               /* fclose(f); file closed after endwhile */
232                               break;
233                           }
234                       } /* endif */
235                   } /* endif ^# */
236                   nfree(line);
237               } /* endwhile */
238               fclose(f);
239           } /* endif */
240           nfree(config->links[i]->floFile);
241           remove(config->links[i]->bsyFile);
242           nfree(config->links[i]->bsyFile);
243       }
244       nfree(config->links[i]->pktFile);
245       nfree(config->links[i]->packFile);
246   } /* endfor */
247 
248   /* send created messages to links */
249   if (rc) sendAreafixMessages();
250 }
251 
init_hptafix(void)252 int init_hptafix(void) {
253   /* vars */
254   af_config      = config;
255   af_cfgFile     = cfgFile;
256   af_app         = &theApp;
257   af_versionStr  = versionStr;
258   af_quiet       = quiet;
259   af_silent_mode = silent_mode;
260   af_report_changes = report_changes;
261   af_send_notify = cmNotifyLink;
262   af_pause = ECHOAREA;
263   /* callbacks and hooks */
264   call_sstrdup  = &safe_strdup;
265   call_smalloc  = &safe_malloc;
266   call_srealloc = &safe_realloc;
267 
268   call_getArea  = &afGetArea;
269   call_isValid  = &afIsValidConference;
270   call_sendMsg  = &afSendMsg;
271   call_writeMsgToSysop = &afWriteMsgToSysop;
272   call_getLinkRobot = &getLinkRobot;
273   hook_onDeleteArea = &afDeleteArea;
274   hook_onRescanArea = &afRescanArea;
275   hook_onAutoCreate = &afReportAutoCreate;
276 #ifdef DO_PERL
277   hook_onConfigChange = &perl_invalidate;
278   hook_echolist       = &perl_echolist;
279   hook_afixcmd        = &perl_afixcmd;
280   hook_afixreq        = &perl_afixreq;
281   hook_robotmsg       = &perl_robotmsg;
282 #endif
283   robot = getRobot(config, "areafix", 0); /* !!! val: change this later !!! */
284   return init_areafix("areafix");
285 }
286