1 /*
2 * Copyright (C) 2001-2012 Jacek Sieka, arnetheduck on gmail point com
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #include "stdinc.h"
20
21 #include "FavoriteManager.h"
22
23 #include "ClientManager.h"
24 #include "CryptoManager.h"
25 //#include "WindowManager.h"
26
27 #include "HttpConnection.h"
28 #include "StringTokenizer.h"
29 #include "SimpleXML.h"
30 #include "UserCommand.h"
31 //#include "WindowInfo.h"
32 #include "File.h"
33 #include "BZUtils.h"
34 #include "FilteredFile.h"
35
36 namespace dcpp {
37
FavoriteManager()38 FavoriteManager::FavoriteManager() : lastId(0), useHttp(false), running(false), c(NULL), lastServer(0), listType(TYPE_NORMAL), dontSave(false) {
39 SettingsManager::getInstance()->addListener(this);
40 ClientManager::getInstance()->addListener(this);
41
42 File::ensureDirectory(Util::getHubListsPath());
43 }
44
~FavoriteManager()45 FavoriteManager::~FavoriteManager() {
46 ClientManager::getInstance()->removeListener(this);
47 SettingsManager::getInstance()->removeListener(this);
48 if(c) {
49 c->removeListener(this);
50 delete c;
51 c = NULL;
52 }
53
54 for_each(favoriteHubs.begin(), favoriteHubs.end(), DeleteFunction());
55 }
56
addUserCommand(int type,int ctx,int flags,const string & name,const string & command,const string & to,const string & hub)57 UserCommand FavoriteManager::addUserCommand(int type, int ctx, int flags, const string& name, const string& command, const string& to, const string& hub) {
58 // No dupes, add it...
59 Lock l(cs);
60 userCommands.push_back(UserCommand(lastId++, type, ctx, flags, name, command, to, hub));
61 UserCommand& uc = userCommands.back();
62 if(!uc.isSet(UserCommand::FLAG_NOSAVE))
63 save();
64 return userCommands.back();
65 }
66
getUserCommand(int cid,UserCommand & uc)67 bool FavoriteManager::getUserCommand(int cid, UserCommand& uc) {
68 Lock l(cs);
69 for(auto i = userCommands.begin(); i != userCommands.end(); ++i) {
70 if(i->getId() == cid) {
71 uc = *i;
72 return true;
73 }
74 }
75 return false;
76 }
77
moveUserCommand(int cid,int pos)78 bool FavoriteManager::moveUserCommand(int cid, int pos) {
79 dcassert(pos == -1 || pos == 1);
80 Lock l(cs);
81 for(auto i = userCommands.begin(); i != userCommands.end(); ++i) {
82 if(i->getId() == cid) {
83 swap(*i, *(i + pos));
84 return true;
85 }
86 }
87 return false;
88 }
89
updateUserCommand(const UserCommand & uc)90 void FavoriteManager::updateUserCommand(const UserCommand& uc) {
91 bool nosave = true;
92 Lock l(cs);
93 for(auto i = userCommands.begin(); i != userCommands.end(); ++i) {
94 if(i->getId() == uc.getId()) {
95 *i = uc;
96 nosave = uc.isSet(UserCommand::FLAG_NOSAVE);
97 break;
98 }
99 }
100 if(!nosave)
101 save();
102 }
103
findUserCommand(const string & aName,const string & aUrl)104 int FavoriteManager::findUserCommand(const string& aName, const string& aUrl) {
105 Lock l(cs);
106 for(auto i = userCommands.begin(); i != userCommands.end(); ++i) {
107 if(i->getName() == aName && i->getHub() == aUrl) {
108 return i->getId();
109 }
110 }
111 return -1;
112 }
113
removeUserCommand(int cid)114 void FavoriteManager::removeUserCommand(int cid) {
115 bool nosave = true;
116 Lock l(cs);
117 for(auto i = userCommands.begin(); i != userCommands.end(); ++i) {
118 if(i->getId() == cid) {
119 nosave = i->isSet(UserCommand::FLAG_NOSAVE);
120 userCommands.erase(i);
121 break;
122 }
123 }
124 if(!nosave)
125 save();
126 }
removeUserCommand(const string & srv)127 void FavoriteManager::removeUserCommand(const string& srv) {
128 Lock l(cs);
129 for(auto i = userCommands.begin(); i != userCommands.end(); ) {
130 if((i->getHub() == srv) && i->isSet(UserCommand::FLAG_NOSAVE)) {
131 i = userCommands.erase(i);
132 } else {
133 ++i;
134 }
135 }
136 }
137
removeHubUserCommands(int ctx,const string & hub)138 void FavoriteManager::removeHubUserCommands(int ctx, const string& hub) {
139 Lock l(cs);
140 for(auto i = userCommands.begin(); i != userCommands.end(); ) {
141 if(i->getHub() == hub && i->isSet(UserCommand::FLAG_NOSAVE) && i->getCtx() & ctx) {
142 i = userCommands.erase(i);
143 } else {
144 ++i;
145 }
146 }
147 }
148
addFavoriteUser(const UserPtr & aUser)149 void FavoriteManager::addFavoriteUser(const UserPtr& aUser) {
150 Lock l(cs);
151 if(users.find(aUser->getCID()) == users.end()) {
152 StringList urls = ClientManager::getInstance()->getHubs(aUser->getCID(), Util::emptyString);
153 StringList nicks = ClientManager::getInstance()->getNicks(aUser->getCID(), Util::emptyString);
154
155 /// @todo make this an error probably...
156 if(urls.empty())
157 urls.push_back(Util::emptyString);
158 if(nicks.empty())
159 nicks.push_back(Util::emptyString);
160
161 auto i = users.insert(make_pair(aUser->getCID(), FavoriteUser(aUser, nicks[0], urls[0]))).first;
162 fire(FavoriteManagerListener::UserAdded(), i->second);
163 save();
164 }
165 }
166
removeFavoriteUser(const UserPtr & aUser)167 void FavoriteManager::removeFavoriteUser(const UserPtr& aUser) {
168 Lock l(cs);
169 auto i = users.find(aUser->getCID());
170 if(i != users.end()) {
171 fire(FavoriteManagerListener::UserRemoved(), i->second);
172 users.erase(i);
173 save();
174 }
175 }
176
getUserURL(const UserPtr & aUser) const177 std::string FavoriteManager::getUserURL(const UserPtr& aUser) const {
178 Lock l(cs);
179 auto i = users.find(aUser->getCID());
180 if(i != users.end()) {
181 const FavoriteUser& fu = i->second;
182 return fu.getUrl();
183 }
184 return Util::emptyString;
185 }
186
addFavorite(const FavoriteHubEntry & aEntry)187 void FavoriteManager::addFavorite(const FavoriteHubEntry& aEntry) {
188 FavoriteHubEntry* f;
189
190 FavoriteHubEntryList::iterator i = getFavoriteHub(aEntry.getServer());
191 if(i != favoriteHubs.end()) {
192 return;
193 }
194 f = new FavoriteHubEntry(aEntry);
195 favoriteHubs.push_back(f);
196 fire(FavoriteManagerListener::FavoriteAdded(), f);
197 save();
198 }
199
removeFavorite(FavoriteHubEntry * entry)200 void FavoriteManager::removeFavorite(FavoriteHubEntry* entry) {
201 FavoriteHubEntryList::iterator i = find(favoriteHubs.begin(), favoriteHubs.end(), entry);
202 if(i == favoriteHubs.end()) {
203 return;
204 }
205
206 fire(FavoriteManagerListener::FavoriteRemoved(), entry);
207 favoriteHubs.erase(i);
208 delete entry;
209 save();
210 }
211
isFavoriteHub(const std::string & url)212 bool FavoriteManager::isFavoriteHub(const std::string& url) {
213 FavoriteHubEntryList::iterator i = getFavoriteHub(url);
214 if(i != favoriteHubs.end()) {
215 return true;
216 }
217 return false;
218 }
219
addFavoriteDir(const string & aDirectory,const string & aName)220 bool FavoriteManager::addFavoriteDir(const string& aDirectory, const string & aName){
221 string path = aDirectory;
222
223 if( path[ path.length() -1 ] != PATH_SEPARATOR )
224 path += PATH_SEPARATOR;
225
226 for(auto i = favoriteDirs.begin(); i != favoriteDirs.end(); ++i) {
227 if((Util::strnicmp(path, i->first, i->first.length()) == 0) && (Util::strnicmp(path, i->first, path.length()) == 0)) {
228 return false;
229 }
230 if(Util::stricmp(aName, i->second) == 0) {
231 return false;
232 }
233 }
234 favoriteDirs.push_back(make_pair(aDirectory, aName));
235 save();
236 return true;
237 }
238
removeFavoriteDir(const string & aName)239 bool FavoriteManager::removeFavoriteDir(const string& aName) {
240 string d(aName);
241
242 if(d[d.length() - 1] != PATH_SEPARATOR)
243 d += PATH_SEPARATOR;
244
245 for(auto j = favoriteDirs.begin(); j != favoriteDirs.end(); ++j) {
246 if(Util::stricmp(j->first.c_str(), d.c_str()) == 0) {
247 favoriteDirs.erase(j);
248 save();
249 return true;
250 }
251 }
252 return false;
253 }
254
renameFavoriteDir(const string & aName,const string & anotherName)255 bool FavoriteManager::renameFavoriteDir(const string& aName, const string& anotherName) {
256
257 for(auto j = favoriteDirs.begin(); j != favoriteDirs.end(); ++j) {
258 if(Util::stricmp(j->second.c_str(), aName.c_str()) == 0) {
259 j->second = anotherName;
260 save();
261 return true;
262 }
263 }
264 return false;
265 }
266
267 class XmlListLoader : public SimpleXMLReader::CallBack {
268 public:
XmlListLoader(HubEntryList & lst)269 XmlListLoader(HubEntryList& lst) : publicHubs(lst) { }
~XmlListLoader()270 virtual ~XmlListLoader() { }
startTag(const string & name,StringPairList & attribs,bool)271 virtual void startTag(const string& name, StringPairList& attribs, bool) {
272 if(name == "Hub") {
273 const string& name = getAttrib(attribs, "Name", 0);
274 const string& server = getAttrib(attribs, "Address", 1);
275 const string& description = getAttrib(attribs, "Description", 2);
276 const string& users = getAttrib(attribs, "Users", 3);
277 const string& country = getAttrib(attribs, "Country", 4);
278 const string& shared = getAttrib(attribs, "Shared", 5);
279 const string& minShare = getAttrib(attribs, "Minshare", 5);
280 const string& minSlots = getAttrib(attribs, "Minslots", 5);
281 const string& maxHubs = getAttrib(attribs, "Maxhubs", 5);
282 const string& maxUsers = getAttrib(attribs, "Maxusers", 5);
283 const string& reliability = getAttrib(attribs, "Reliability", 5);
284 const string& rating = getAttrib(attribs, "Rating", 5);
285 publicHubs.push_back(HubEntry(name, server, description, users, country, shared, minShare, minSlots, maxHubs, maxUsers, reliability, rating));
286 }
287 }
endTag(const string &,const string &)288 virtual void endTag(const string&, const string&) {
289
290 }
291 private:
292 HubEntryList& publicHubs;
293 };
294
onHttpFinished(bool fromHttp)295 bool FavoriteManager::onHttpFinished(bool fromHttp) noexcept {
296 MemoryInputStream mis(downloadBuf);
297 bool success = true;
298
299 Lock l(cs);
300 HubEntryList& list = publicListMatrix[publicListServer];
301 list.clear();
302
303 try {
304 XmlListLoader loader(list);
305
306 if((listType == TYPE_BZIP2) && (!downloadBuf.empty())) {
307 FilteredInputStream<UnBZFilter, false> f(&mis);
308 SimpleXMLReader(&loader).parse(f);
309 } else {
310 SimpleXMLReader(&loader).parse(mis);
311 }
312 } catch(const Exception&) {
313 success = false;
314 fire(FavoriteManagerListener::Corrupted(), fromHttp ? publicListServer : Util::emptyString);
315 }
316
317 if(fromHttp) {
318 try {
319 File f(Util::getHubListsPath() + Util::validateFileName(publicListServer, "/"), File::WRITE, File::CREATE | File::TRUNCATE);
320 f.write(downloadBuf);
321 f.close();
322 } catch(const FileException&) { }
323 }
324
325 downloadBuf = Util::emptyString;
326
327 return success;
328 }
329
save()330 void FavoriteManager::save() {
331 if(dontSave)
332 return;
333
334 Lock l(cs);
335 try {
336 SimpleXML xml;
337
338 xml.addTag("Favorites");
339 xml.stepIn();
340
341 xml.addTag("Hubs");
342 xml.stepIn();
343
344 for(auto i = favHubGroups.begin(), iend = favHubGroups.end(); i != iend; ++i) {
345 xml.addTag("Group");
346 xml.addChildAttrib("Name", i->first);
347 xml.addChildAttrib("Private", i->second.priv);
348 xml.addChildAttrib("Connect", i->second.connect);
349 }
350
351 for(auto i = favoriteHubs.begin(), iend = favoriteHubs.end(); i != iend; ++i) {
352 xml.addTag("Hub");
353 xml.addChildAttrib("Name", (*i)->getName());
354 xml.addChildAttrib("Connect", (*i)->getConnect());
355 xml.addChildAttrib("Description", (*i)->getDescription());
356 xml.addChildAttrib("Nick", (*i)->getNick(false));
357 xml.addChildAttrib("Password", (*i)->getPassword());
358 xml.addChildAttrib("Server", (*i)->getServer());
359 xml.addChildAttrib("UserDescription", (*i)->getUserDescription());
360 xml.addChildAttrib("Encoding", (*i)->getEncoding());
361 xml.addChildAttrib("ClientId", (*i)->getClientId());
362 xml.addChildAttrib("ExternalIP", (*i)->getExternalIP());
363 xml.addChildAttrib("OverrideId", Util::toString((*i)->getOverrideId()));
364 xml.addChildAttrib("UseInternetIp",(*i)->getUseInternetIP());
365 xml.addChildAttrib("DisableChat", (*i)->getDisableChat());
366 xml.addChildAttrib("Mode", Util::toString((*i)->getMode()));
367 xml.addChildAttrib("SearchInterval", Util::toString((*i)->getSearchInterval()));
368 xml.addChildAttrib("Group", (*i)->getGroup());
369 }
370 xml.stepOut();
371 xml.addTag("Users");
372 xml.stepIn();
373 for(auto i = users.begin(), iend = users.end(); i != iend; ++i) {
374 xml.addTag("User");
375 xml.addChildAttrib("LastSeen", i->second.getLastSeen());
376 xml.addChildAttrib("GrantSlot", i->second.isSet(FavoriteUser::FLAG_GRANTSLOT));
377 xml.addChildAttrib("UserDescription", i->second.getDescription());
378 xml.addChildAttrib("Nick", i->second.getNick());
379 xml.addChildAttrib("URL", i->second.getUrl());
380 xml.addChildAttrib("CID", i->first.toBase32());
381 }
382 xml.stepOut();
383 xml.addTag("UserCommands");
384 xml.stepIn();
385 for(auto i = userCommands.begin(), iend = userCommands.end(); i != iend; ++i) {
386 if(!i->isSet(UserCommand::FLAG_NOSAVE)) {
387 xml.addTag("UserCommand");
388 xml.addChildAttrib("Type", i->getType());
389 xml.addChildAttrib("Context", i->getCtx());
390 xml.addChildAttrib("Name", i->getName());
391 xml.addChildAttrib("Command", i->getCommand());
392 xml.addChildAttrib("To", i->getTo());
393 xml.addChildAttrib("Hub", i->getHub());
394 }
395 }
396 xml.stepOut();
397 //Favorite download to dirs
398 xml.addTag("FavoriteDirs");
399 xml.stepIn();
400 StringPairList spl = getFavoriteDirs();
401 for(auto i = spl.begin(), iend = spl.end(); i != iend; ++i) {
402 xml.addTag("Directory", i->first);
403 xml.addChildAttrib("Name", i->second);
404 }
405 xml.stepOut();
406
407 xml.stepOut();
408
409 string fname = getConfigFile();
410
411 File f(fname + ".tmp", File::WRITE, File::CREATE | File::TRUNCATE);
412 f.write(SimpleXML::utf8Header);
413 f.write(xml.toXML());
414 f.close();
415 File::deleteFile(fname);
416 File::renameFile(fname + ".tmp", fname);
417
418 } catch(const Exception& e) {
419 dcdebug("FavoriteManager::save: %s\n", e.getError().c_str());
420 }
421 }
422
load()423 void FavoriteManager::load() {
424
425 // Add NMDC standard op commands
426 static const char kickstr[] =
427 "$To: %[userNI] From: %[myNI] $<%[myNI]> You are being kicked because: %[line:Reason]|<%[myNI]> is kicking %[userNI] because: %[line:Reason]|$Kick %[userNI]|";
428 addUserCommand(UserCommand::TYPE_RAW_ONCE, UserCommand::CONTEXT_USER | UserCommand::CONTEXT_SEARCH, UserCommand::FLAG_NOSAVE,
429 _("Kick user(s)"), kickstr, "", "op");
430 static const char redirstr[] =
431 "$OpForceMove $Who:%[userNI]$Where:%[line:Target Server]$Msg:%[line:Message]|";
432 addUserCommand(UserCommand::TYPE_RAW_ONCE, UserCommand::CONTEXT_USER | UserCommand::CONTEXT_SEARCH, UserCommand::FLAG_NOSAVE,
433 _("Redirect user(s)"), redirstr, "", "op");
434
435 try {
436 SimpleXML xml;
437 Util::migrate(getConfigFile());
438 xml.fromXML(File(getConfigFile(), File::READ, File::OPEN).read());
439
440 if(xml.findChild("Favorites")) {
441 xml.stepIn();
442 load(xml);
443 xml.stepOut();
444 }
445 } catch(const Exception& e) {
446 dcdebug("FavoriteManager::load: %s\n", e.getError().c_str());
447 }
448 }
449
load(SimpleXML & aXml)450 void FavoriteManager::load(SimpleXML& aXml) {
451 dontSave = true;
452 bool needSave = false;
453
454 aXml.resetCurrentChild();
455 if(aXml.findChild("Hubs")) {
456 aXml.stepIn();
457
458 while(aXml.findChild("Group")) {
459 string name = aXml.getChildAttrib("Name");
460 if(name.empty())
461 continue;
462 FavHubGroupProperties props = { aXml.getBoolChildAttrib("Private"), aXml.getBoolChildAttrib("Connect") };
463 favHubGroups[name] = props;
464 }
465
466 aXml.resetCurrentChild();
467 while(aXml.findChild("Hub")) {
468 FavoriteHubEntry* e = new FavoriteHubEntry();
469 e->setName(aXml.getChildAttrib("Name"));
470 e->setConnect(aXml.getBoolChildAttrib("Connect"));
471 e->setDescription(aXml.getChildAttrib("Description"));
472 e->setNick(aXml.getChildAttrib("Nick"));
473 e->setPassword(aXml.getChildAttrib("Password"));
474 e->setServer(aXml.getChildAttrib("Server"));
475 e->setUserDescription(aXml.getChildAttrib("UserDescription"));
476 e->setEncoding(aXml.getChildAttrib("Encoding"));
477 e->setExternalIP(aXml.getChildAttrib("ExternalIP"));
478 e->setClientId(aXml.getChildAttrib("ClientId"));
479 e->setOverrideId(Util::toInt(aXml.getChildAttrib("OverrideId")) != 0);
480 e->setUseInternetIP(aXml.getBoolChildAttrib("UseInternetIp"));
481 e->setDisableChat(aXml.getBoolChildAttrib("DisableChat"));
482 e->setMode(Util::toInt(aXml.getChildAttrib("Mode")));
483 e->setSearchInterval(Util::toInt(aXml.getChildAttrib("SearchInterval")));
484 e->setGroup(aXml.getChildAttrib("Group"));
485 favoriteHubs.push_back(e);
486
487 if(aXml.getBoolChildAttrib("Connect")) {
488 // this entry dates from before the window manager & fav hub groups; convert it.
489 const string name = _("Auto-connect group (converted)");
490 if(favHubGroups.find(name) == favHubGroups.end()) {
491 FavHubGroupProperties props = { false, true };
492 favHubGroups[name] = props;
493 }
494 e->setGroup(name);
495 needSave = true;
496 }
497 }
498 aXml.stepOut();
499 }
500 // parse groups that have the "Connect" param and send their hubs to WindowManager
501 //for(auto i = favHubGroups.begin(), iend = favHubGroups.end(); i != iend; ++i) {
502 //if(i->second.connect) {
503 //FavoriteHubEntryList hubs = getFavoriteHubs(i->first);
504 //for(auto hub = hubs.begin(), hub_end = hubs.end(); hub != hub_end; ++hub) {
505 //StringMap map;
506 //map[WindowInfo::address] = (*hub)->getServer();
507 //WindowManager::getInstance()->add(WindowManager::hub(), map);
508 //}
509 //}
510 //}
511
512 aXml.resetCurrentChild();
513 if(aXml.findChild("Users")) {
514 aXml.stepIn();
515 while(aXml.findChild("User")) {
516 UserPtr u;
517 const string& cid = aXml.getChildAttrib("CID");
518 const string& nick = aXml.getChildAttrib("Nick");
519 const string& hubUrl = aXml.getChildAttrib("URL");
520
521 if(cid.length() != 39) {
522 if(nick.empty() || hubUrl.empty())
523 continue;
524 u = ClientManager::getInstance()->getUser(nick, hubUrl);
525 } else {
526 u = ClientManager::getInstance()->getUser(CID(cid));
527 }
528 auto i = users.insert(make_pair(u->getCID(), FavoriteUser(u, nick, hubUrl))).first;
529
530 if(aXml.getBoolChildAttrib("GrantSlot"))
531 i->second.setFlag(FavoriteUser::FLAG_GRANTSLOT);
532
533 i->second.setLastSeen((uint32_t)aXml.getIntChildAttrib("LastSeen"));
534 i->second.setDescription(aXml.getChildAttrib("UserDescription"));
535
536 }
537 aXml.stepOut();
538 }
539 aXml.resetCurrentChild();
540 if(aXml.findChild("UserCommands")) {
541 aXml.stepIn();
542 while(aXml.findChild("UserCommand")) {
543 addUserCommand(aXml.getIntChildAttrib("Type"), aXml.getIntChildAttrib("Context"), 0, aXml.getChildAttrib("Name"),
544 aXml.getChildAttrib("Command"), aXml.getChildAttrib("To"), aXml.getChildAttrib("Hub"));
545 }
546 aXml.stepOut();
547 }
548 //Favorite download to dirs
549 aXml.resetCurrentChild();
550 if(aXml.findChild("FavoriteDirs")) {
551 aXml.stepIn();
552 while(aXml.findChild("Directory")) {
553 string virt = aXml.getChildAttrib("Name");
554 string d(aXml.getChildData());
555 FavoriteManager::getInstance()->addFavoriteDir(d, virt);
556 }
557 aXml.stepOut();
558 }
559
560 dontSave = false;
561 if(needSave)
562 save();
563 }
564
userUpdated(const OnlineUser & info)565 void FavoriteManager::userUpdated(const OnlineUser& info) {
566 Lock l(cs);
567 auto i = users.find(info.getUser()->getCID());
568 if(i != users.end()) {
569 FavoriteUser& fu = i->second;
570 fu.update(info);
571 save();
572 }
573 }
574
getFavoriteHubEntry(const string & aServer) const575 FavoriteHubEntryPtr FavoriteManager::getFavoriteHubEntry(const string& aServer) const {
576 for(auto i = favoriteHubs.begin(), iend = favoriteHubs.end(); i != iend; ++i) {
577 FavoriteHubEntry* hub = *i;
578 if(Util::stricmp(hub->getServer(), aServer) == 0) {
579 return hub;
580 }
581 }
582 return NULL;
583 }
584
getFavoriteHubs(const string & group) const585 FavoriteHubEntryList FavoriteManager::getFavoriteHubs(const string& group) const {
586 FavoriteHubEntryList ret;
587 for(auto i = favoriteHubs.begin(), iend = favoriteHubs.end(); i != iend; ++i)
588 if((*i)->getGroup() == group)
589 ret.push_back(*i);
590 return ret;
591 }
592
isPrivate(const string & url) const593 bool FavoriteManager::isPrivate(const string& url) const {
594 if(url.empty())
595 return false;
596
597 FavoriteHubEntry* fav = getFavoriteHubEntry(url);
598 if(fav) {
599 const string& name = fav->getGroup();
600 if(!name.empty()) {
601 auto group = favHubGroups.find(name);
602 if(group != favHubGroups.end())
603 return group->second.priv;
604 }
605 }
606 return false;
607 }
608
hasSlot(const UserPtr & aUser) const609 bool FavoriteManager::hasSlot(const UserPtr& aUser) const {
610 Lock l(cs);
611 auto i = users.find(aUser->getCID());
612 if(i == users.end())
613 return false;
614 return i->second.isSet(FavoriteUser::FLAG_GRANTSLOT);
615 }
616
getLastSeen(const UserPtr & aUser) const617 time_t FavoriteManager::getLastSeen(const UserPtr& aUser) const {
618 Lock l(cs);
619 auto i = users.find(aUser->getCID());
620 if(i == users.end())
621 return 0;
622 return i->second.getLastSeen();
623 }
624
setAutoGrant(const UserPtr & aUser,bool grant)625 void FavoriteManager::setAutoGrant(const UserPtr& aUser, bool grant) {
626 Lock l(cs);
627 auto i = users.find(aUser->getCID());
628 if(i == users.end())
629 return;
630 if(grant)
631 i->second.setFlag(FavoriteUser::FLAG_GRANTSLOT);
632 else
633 i->second.unsetFlag(FavoriteUser::FLAG_GRANTSLOT);
634 save();
635 }
setUserDescription(const UserPtr & aUser,const string & description)636 void FavoriteManager::setUserDescription(const UserPtr& aUser, const string& description) {
637 Lock l(cs);
638 auto i = users.find(aUser->getCID());
639 if(i == users.end())
640 return;
641 i->second.setDescription(description);
642 save();
643 }
644
getHubLists()645 StringList FavoriteManager::getHubLists() {
646 StringTokenizer<string> lists(SETTING(HUBLIST_SERVERS), ';');
647 return lists.getTokens();
648 }
649
getFavoriteHub(const string & aServer)650 FavoriteHubEntryList::iterator FavoriteManager::getFavoriteHub(const string& aServer) {
651 for(FavoriteHubEntryList::iterator i = favoriteHubs.begin(); i != favoriteHubs.end(); ++i) {
652 if(Util::stricmp((*i)->getServer(), aServer) == 0) {
653 return i;
654 }
655 }
656 return favoriteHubs.end();
657 }
658
659
setHubList(int aHubList)660 void FavoriteManager::setHubList(int aHubList) {
661 lastServer = aHubList;
662 refresh();
663 }
664
refresh(bool forceDownload)665 void FavoriteManager::refresh(bool forceDownload /* = false */) {
666 StringList sl = getHubLists();
667 if(sl.empty())
668 return;
669 publicListServer = sl[(lastServer) % sl.size()];
670 if(Util::strnicmp(publicListServer.c_str(), "http://", 7) != 0) {
671 lastServer++;
672 return;
673 }
674
675 if(!forceDownload) {
676 string path = Util::getHubListsPath() + Util::validateFileName(publicListServer, "/");
677 if(File::getSize(path) > 0) {
678 useHttp = false;
679 string fileDate;
680 {
681 Lock l(cs);
682 publicListMatrix[publicListServer].clear();
683 }
684 listType = (Util::stricmp(path.substr(path.size() - 4), ".bz2") == 0) ? TYPE_BZIP2 : TYPE_NORMAL;
685 try {
686 File cached(path, File::READ, File::OPEN);
687 downloadBuf = cached.read();
688 char buf[20];
689 time_t fd = cached.getLastModified();
690 if (strftime(buf, 20, "%x", localtime(&fd))) {
691 fileDate = string(buf);
692 }
693 } catch(const FileException&) {
694 downloadBuf = Util::emptyString;
695 }
696 if(!downloadBuf.empty()) {
697 if (onHttpFinished(false)) {
698 fire(FavoriteManagerListener::LoadedFromCache(), publicListServer, fileDate);
699 }
700 return;
701 }
702 }
703 }
704
705 if(!running) {
706 useHttp = true;
707 {
708 Lock l(cs);
709 publicListMatrix[publicListServer].clear();
710 }
711 fire(FavoriteManagerListener::DownloadStarting(), publicListServer);
712 if(c == NULL)
713 c = new HttpConnection();
714 c->addListener(this);
715 c->downloadFile(publicListServer);
716 running = true;
717 }
718 }
719
getUserCommands(int ctx,const StringList & hubs)720 UserCommand::List FavoriteManager::getUserCommands(int ctx, const StringList& hubs) {
721 vector<bool> isOp(hubs.size());
722
723 for(size_t i = 0; i < hubs.size(); ++i) {
724 if(ClientManager::getInstance()->isOp(ClientManager::getInstance()->getMe(), hubs[i])) {
725 isOp[i] = true;
726 }
727 }
728
729 Lock l(cs);
730 UserCommand::List lst;
731 for(auto i = userCommands.begin(); i != userCommands.end(); ++i) {
732 UserCommand& uc = *i;
733 if(!(uc.getCtx() & ctx)) {
734 //printf("%s\n", uc.getName().c_str());
735 //printf("false\n");
736 continue;
737 }
738 for(size_t j = 0; j < hubs.size(); ++j) {
739 const string& hub = hubs[j];
740 bool hubAdc = hub.compare(0, 6, "adc://") == 0 || hub.compare(0, 7, "adcs://") == 0;
741 bool commandAdc = uc.getHub().compare(0, 6, "adc://") == 0 || uc.getHub().compare(0, 7, "adcs://") == 0;
742 if(hubAdc && commandAdc) {
743 if((uc.getHub() == "adc://" || uc.getHub() == "adcs://") ||
744 ((uc.getHub() == "adc://op" || uc.getHub() == "adcs://op") && isOp[j]) ||
745 (uc.getHub() == hub) )
746 {
747 //printf("Found ADC command for ADC hub.\n");
748 lst.push_back(*i);
749 break;
750 }
751 } else if((!hubAdc && !commandAdc) || uc.isChat()) {
752 if((uc.getHub().length() == 0) ||
753 (uc.getHub() == "op" && isOp[j]) ||
754 (uc.getHub() == hub) )
755 {
756 //printf("Found non-ADC command for non-ADC hub.\n");
757 lst.push_back(*i);
758 break;
759 }
760 }
761 }
762 }
763 return lst;
764 }
765
766 // HttpConnectionListener
on(Data,HttpConnection *,const uint8_t * buf,size_t len)767 void FavoriteManager::on(Data, HttpConnection*, const uint8_t* buf, size_t len) noexcept {
768 if(useHttp)
769 downloadBuf.append((const char*)buf, len);
770 }
771
on(Failed,HttpConnection *,const string & aLine)772 void FavoriteManager::on(Failed, HttpConnection*, const string& aLine) noexcept {
773 c->removeListener(this);
774 lastServer++;
775 running = false;
776 if(useHttp){
777 downloadBuf = Util::emptyString;
778 fire(FavoriteManagerListener::DownloadFailed(), aLine);
779 }
780 }
on(Complete,HttpConnection *,const string & aLine,bool fromCoral)781 void FavoriteManager::on(Complete, HttpConnection*, const string& aLine, bool fromCoral) noexcept {
782 bool parseSuccess = false;
783
784 c->removeListener(this);
785 if(useHttp) {
786 parseSuccess = onHttpFinished(true);
787 }
788 running = false;
789 if(parseSuccess) {
790 fire(FavoriteManagerListener::DownloadFinished(), aLine, fromCoral);
791 }
792 }
793
on(Retried,HttpConnection *,const bool Connected)794 void FavoriteManager::on(Retried, HttpConnection*, const bool Connected) noexcept {
795 if (Connected)
796 downloadBuf = Util::emptyString;
797 }
798
on(Redirected,HttpConnection *,const string & aLine)799 void FavoriteManager::on(Redirected, HttpConnection*, const string& aLine) noexcept {
800 if(useHttp)
801 fire(FavoriteManagerListener::DownloadStarting(), aLine);
802 }
on(TypeNormal,HttpConnection *)803 void FavoriteManager::on(TypeNormal, HttpConnection*) noexcept {
804 if(useHttp)
805 listType = TYPE_NORMAL;
806 }
on(TypeBZ2,HttpConnection *)807 void FavoriteManager::on(TypeBZ2, HttpConnection*) noexcept {
808 if(useHttp)
809 listType = TYPE_BZIP2;
810 }
811
on(UserUpdated,const OnlineUser & user)812 void FavoriteManager::on(UserUpdated, const OnlineUser& user) noexcept {
813 userUpdated(user);
814 }
815
816 //NOTE: freedcpp
on(UserDisconnected,const UserPtr & user)817 void FavoriteManager::on(UserDisconnected, const UserPtr& user) noexcept {
818 Lock l(cs);
819
820 auto i = users.find(user->getCID());
821 if (i != users.end())
822 {
823 i->second.setLastSeen(GET_TIME());
824 fire(FavoriteManagerListener::StatusChanged(), i->second);
825 save();
826 }
827 }
828
on(UserConnected,const UserPtr & user)829 void FavoriteManager::on(UserConnected, const UserPtr& user) noexcept {
830 Lock l(cs);
831
832 auto i = users.find(user->getCID());
833 if (i != users.end())
834 fire(FavoriteManagerListener::StatusChanged(), i->second);
835 }
836
getConfigFile()837 string FavoriteManager::getConfigFile() {
838 return Util::getPath(Util::PATH_USER_CONFIG) + "Favorites.xml";
839 }
840 //NOTE: freedcpp
841 } // namespace dcpp
842