moved the old Changelog, which only contained log from the old centericq
[centerim.git] / src / eventmanager.cc
blobc4cd8b1bd9152915ca9bc13f253ab4b1ae9dcb92
1 /*
3 * centerim event manager class
4 * $Id: eventmanager.cc,v 1.27 2005/08/28 01:33:21 konst Exp $
6 * Copyright (C) 2001,2002 by Konstantin Klyagin <k@thekonst.net>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
25 #include "eventmanager.h"
26 #include "icqmlist.h"
27 #include "icqconf.h"
28 #include "icqface.h"
29 #include "icqcontacts.h"
30 #include "abstracthook.h"
31 #include "imlogger.h"
32 #include "imexternal.h"
33 #include "captcha.h"
35 imeventmanager em;
37 imeventmanager::imeventmanager(): unsent(0), lastevent(0), recentlysent(0) {
40 imeventmanager::~imeventmanager() {
43 void imeventmanager::store(const imevent &cev) {
44 icqcontact *c;
45 bool proceed;
47 auto_ptr<imevent> icev(cev.getevent());
48 imevent &ev = *icev.get();
50 static int preoptions[imevent::imdirection_size] = {
51 imexternal::aoprereceive,
52 imexternal::aopresend
55 external.exec(&ev, proceed, preoptions[ev.getdirection()]);
57 if(!proceed)
58 return;
60 if(ev.getdirection() == imevent::incoming) {
61 if(!lst.inlist(ev.getcontact(), csignore)) {
62 logger.putevent(ev);
64 c = clist.get(ev.getcontact());
66 if(!c) {
67 proceed = !conf.getantispam() ||
68 ((ev.gettype() == imevent::authorization) && !conf.getdropauthreq()) ||
69 conf.getusingcaptcha();
71 if(proceed) {
72 c = clist.addnew(ev.getcontact());
73 /* turing test */
74 if (conf.getdebug()) face.log("captcha: enabled = %i", conf.getusingcaptcha());
75 if (conf.getusingcaptcha()) {
76 if (conf.getdebug()) face.log("captcha: start");
77 /* If the turing test was failed or not completed, remove
78 * contact (WE DONT WANT YOU!)
79 * Note tat below, we always remove the contact if it is not verified */
80 if (!conf.thecaptcha.docaptcha(ev.getcontact())) {
81 if (conf.getdebug()) face.log("captcha: starting a new turing test with: %s", ev.getcontact().totext().c_str());
82 /* have not started the turing test, so send our greeter and message */
83 store(immessage(
84 c->getdesc(), imevent::outgoing,
85 conf.getcaptchagreet() + "\n" +
86 conf.thecaptcha.getcaptchaquestion(ev.getcontact())));
87 clist.remove(c->getdesc());
88 c = 0;
89 } else {
90 if(conf.getdebug()) face.log("captcha: got an answer: %s", ev.gettext().c_str());
91 /* have started the test, now must verify the answer */
92 if (conf.thecaptcha.checkcaptcha(ev.getcontact(), ev.gettext())) {
93 if (conf.getdebug()) face.log("captcha: received correct answer");
94 /* good, a human */
95 store(immessage(
96 c->getdesc(), imevent::outgoing,
97 conf.getcaptchasuccess()));
98 conf.thecaptcha.donecaptcha(ev.getcontact());
99 } else {
100 if (conf.getdebug()) face.log("captcha: received intorrent answer");
101 /* bad, a computer (or very dumb human :) */
102 store(immessage(
103 c->getdesc(), imevent::outgoing,
104 conf.getcaptchafailure() + "\n" +
105 conf.thecaptcha.getcaptchaquestion(ev.getcontact())));
106 clist.remove(c->getdesc());
107 c = 0;
110 if (conf.getdebug()) face.log("captcha: end");
112 } else {
113 face.log("Dropped an authorization request from %s", ev.getcontact().totext().c_str());
117 if (c) {
118 face.xtermtitle(_("event from %s (%s)"), cev.getcontact().totext().c_str(), c->getdispnick().c_str());
119 eventwrite(ev, history);
121 c->sethasevents(true);
122 c->playsound(ev.gettype());
124 external.exec(ev);
126 face.relaxedupdate();
129 } else if(ev.getdirection() == imevent::outgoing) {
130 abstracthook *hook;
132 // All the SMSes are to be sent through the icqhook class..
134 if(ev.gettype() == imevent::sms) {
135 hook = &gethook(icq);
136 } else {
137 hook = &gethook(ev.getcontact().pname);
140 // Some self-flood protection..
142 if(time(0)-lastevent > PERIOD_ATONCE)
143 recentlysent = 0;
145 proceed = (hook->logged() || ev.getcontact().pname == rss)
146 && recentlysent < MAX_ATONCE;
148 // 3.. 2.. 1.. LAUNCH!
150 if(proceed) {
151 if(hook->send(ev)) {
152 eventwrite(cev, history);
153 logger.putevent(cev);
154 face.xtermtitle();
155 time(&lastevent);
156 recentlysent++;
157 } else {
158 eventwrite(cev, offline);
160 } else {
161 eventwrite(cev, offline);
166 vector<imevent *> imeventmanager::getevents(const imcontact &cont, time_t lastread) const {
167 ifstream fhist;
168 imevent *rev;
169 vector<imevent *> r;
170 icqcontact *c = clist.get(cont);
172 if(c) {
173 fhist.open((c->getdirname() + "history").c_str());
175 if(fhist.is_open()) {
176 if(lastread) {
177 fhist.seekg(c->gethistoffset(), ios::beg);
180 while(!fhist.eof()) {
181 rev = eventread(fhist);
183 if(rev) {
184 if(rev->gettimestamp() > lastread) {
185 rev->setcontact(cont);
186 r.push_back(rev);
187 } else {
188 delete rev;
193 fhist.close();
194 } else {
198 return r;
201 void imeventmanager::eventwrite(const imevent &ev, eventwritemode mode) {
202 ofstream fhist;
203 string fname, lockfname;
204 icqcontact *c;
206 if(c = clist.get(ev.getcontact())) {
207 switch(mode) {
208 case history:
209 fname = c->getdirname() + "history";
210 break;
211 case offline:
212 fname = c->getdirname() + "offline";
213 unsent++;
214 face.relaxedupdate();
215 break;
218 setlock(fname);
220 fhist.open(fname.c_str(), ios::app);
222 if(fhist.is_open()) {
223 ev.write(fhist);
224 fhist.close();
227 releaselock(fname);
231 imevent *imeventmanager::eventread(ifstream &f) const {
232 imevent *rev, ev(f);
234 if(rev = ev.getevent()) {
235 rev->read(f);
237 if(rev->gettype() == imevent::imeventtype_size) {
238 delete rev;
239 rev = 0;
243 return rev;
246 void imeventmanager::resend() {
247 icqcontact *c;
248 imevent *rev;
249 string fname, tfname;
250 ifstream f;
251 int i;
253 for(unsent = i = 0; i < clist.count; i++) {
254 c = (icqcontact *) clist.at(i);
256 fname = c->getdirname() + "offline";
257 tfname = fname + "_";
259 if(!access(fname.c_str(), F_OK))
260 if(!rename(fname.c_str(), tfname.c_str())) {
261 f.open(tfname.c_str());
263 if(f.is_open()) {
264 while(!f.eof()) {
265 rev = eventread(f);
267 if(rev) {
268 rev->setcontact(c->getdesc());
270 if(rev->gettimestamp() > PERIOD_RESEND) {
271 store(*rev);
272 } else {
273 eventwrite(*rev, offline);
276 delete rev;
280 f.close();
281 f.clear();
284 unlink(tfname.c_str());
289 int imeventmanager::getunsentcount() const {
290 return unsent;
293 void imeventmanager::setlock(const string &fname) const {
294 string lockfname = fname + ".lock";
295 int ntries = 0;
296 ofstream f;
298 while(!access(lockfname.c_str(), F_OK) && (ntries < 10)) {
299 usleep(10);
300 ntries++;
303 f.open(lockfname.c_str());
304 if(f.is_open()) f.close();
307 void imeventmanager::releaselock(const string &fname) const {
308 string lockfname = fname + ".lock";
309 unlink(lockfname.c_str());