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 #pragma once
20 
21 #include "TimerManager.h"
22 #include "Client.h"
23 #include "Singleton.h"
24 #include "SettingsManager.h"
25 #include "User.h"
26 #include "Socket.h"
27 #include "ClientManagerListener.h"
28 
29 namespace dcpp {
30 
31 class UserCommand;
32 
33 class ClientManager : public Speaker<ClientManagerListener>,
34     private ClientListener, public Singleton<ClientManager>,
35     private TimerManagerListener
36 {
37 public:
38     Client* getClient(const string& aHubURL);
39     void putClient(Client* aClient);
40 
41     size_t getUserCount() const;
42     int64_t getAvailable() const;
43 
44     StringList getHubs(const CID& cid, const string& hintUrl);
45     StringList getHubNames(const CID& cid, const string& hintUrl);
46     StringList getNicks(const CID& cid, const string& hintUrl);
47     string getField(const CID& cid, const string& hintUrl, const char* field) const;
48 
49     StringList getHubs(const CID& cid, const string& hintUrl, bool priv);
50     StringList getHubNames(const CID& cid, const string& hintUrl, bool priv);
51     StringList getNicks(const CID& cid, const string& hintUrl, bool priv);
52 
getNicks(const HintedUser & user)53     StringList getNicks(const HintedUser& user) { return getNicks(user.user->getCID(), user.hint); }
getHubNames(const HintedUser & user)54     StringList getHubNames(const HintedUser& user) { return getHubNames(user.user->getCID(), user.hint); }
getHubs(const HintedUser & user)55     StringList getHubs(const HintedUser& user) { return getHubs(user.user->getCID(), user.hint); }
56 
57     string getConnection(const CID& cid) const;
58     uint8_t getSlots(const CID& cid) const;
59 
60     bool isConnected(const string& aUrl) const;
61 
62     void search(int aSizeMode, int64_t aSize, int aFileType, const string& aString, const string& aToken, void* aOwner = 0);
63     uint64_t search(StringList& who, int aSizeMode, int64_t aSize, int aFileType, const string& aString, const string& aToken, const StringList& aExtList, void* aOwner = 0);
64     void cancelSearch(void* aOwner);
65 
66     void infoUpdated();
67 
68     UserPtr getUser(const string& aNick, const string& aHubUrl) noexcept;
69     UserPtr getUser(const CID& cid) noexcept;
70 
71     string findHub(const string& ipPort) const;
72     string findHubEncoding(const string& aUrl) const;
73 
74     /**
75     * @param priv discard any user that doesn't match the hint.
76     * @return OnlineUser* found by CID and hint; might be only by CID if priv is false.
77     */
78     OnlineUser* findOnlineUser(const HintedUser& user, bool priv);
79     OnlineUser* findOnlineUser(const CID& cid, const string& hintUrl, bool priv);
80 
findUser(const string & aNick,const string & aHubUrl)81     UserPtr findUser(const string& aNick, const string& aHubUrl) const noexcept { return findUser(makeCid(aNick, aHubUrl)); }
82     UserPtr findUser(const CID& cid) const noexcept;
83     UserPtr findLegacyUser(const string& aNick) const noexcept;
84 
isOnline(const UserPtr & aUser)85     bool isOnline(const UserPtr& aUser) const {
86         Lock l(cs);
87         return onlineUsers.find(aUser->getCID()) != onlineUsers.end();
88     }
89 
getOnlineUserIdentity(const UserPtr & aUser)90     Identity getOnlineUserIdentity(const UserPtr& aUser) const {
91         Lock l(cs);
92         OnlineMap::const_iterator i;
93         i=onlineUsers.find(aUser->getCID());
94         if ( i != onlineUsers.end() )
95         {
96             return i->second->getIdentity();
97         }
98         return Identity();
99     }
100 
getBytesShared(const UserPtr & p)101     int64_t getBytesShared(const UserPtr& p) const{
102         int64_t l_share = 0;
103         {
104             Lock l ( cs );
105             OnlineIterC i = onlineUsers.find ( *const_cast<CID*> ( &p->getCID() ) );
106             if ( i != onlineUsers.end() )
107                 l_share = i->second->getIdentity().getBytesShared();
108         }
109         return l_share;
110     }
111 
112     void setIPUser(const UserPtr& user, const string& IP, uint16_t udpPort = 0) {
113         if(IP.empty())
114             return;
115 
116         Lock l(cs);
117         OnlineMap::const_iterator i = onlineUsers.find(user->getCID());
118         if ( i != onlineUsers.end() ) {
119             i->second->getIdentity().setIp(IP);
120             if(udpPort > 0)
121                 i->second->getIdentity().setUdpPort(Util::toString(udpPort));
122         }
123     }
124 
125     bool isOp(const UserPtr& aUser, const string& aHubUrl) const;
126 
127     /** Constructs a synthetic, hopefully unique CID */
128     CID makeCid(const string& nick, const string& hubUrl) const noexcept;
129 
130     void putOnline(OnlineUser* ou) noexcept;
131     void putOffline(OnlineUser* ou, bool disconnect = false) noexcept;
132 
133     UserPtr& getMe();
134 
135     void send(AdcCommand& c, const CID& to);
136     void connect(const HintedUser& user, const string& token);
137     void privateMessage(const HintedUser& user, const string& msg, bool thirdPerson);
138     void userCommand(const HintedUser& user, const UserCommand& uc, StringMap& params, bool compatibility);
139     int getMode(const string& aHubUrl) const;
140     bool isActive(const string& aHubUrl = Util::emptyString) const { return getMode(aHubUrl) != SettingsManager::INCOMING_FIREWALL_PASSIVE; }
141     static bool ucExecuteLua(const string& cmd, StringMap& params) noexcept;
142 
143 #ifdef DO_NOT_USE_MUTEX
lock()144     void lock() noexcept { cs.lock(); }
unlock()145     void unlock() noexcept { cs.unlock(); }
146 #else // DO_NOT_USE_MUTEX
lock()147     Lock lock() { return Lock(cs); }
148 #endif // DO_NOT_USE_MUTEX
149 
getClients()150     Client::List& getClients() { return clients; }
151 
152     CID getMyCID();
153     const CID& getMyPID();
154 
155     void loadUsers();
156     void saveUsers() const;
157     void saveUser(const CID& cid);
158 #ifdef WITH_DHT
159     OnlineUserPtr findDHTNode(const CID& cid) const;
160 #endif
161 
162 private:
163     typedef unordered_map<string, UserPtr> LegacyMap;
164     typedef LegacyMap::iterator LegacyIter;
165 
166     typedef unordered_map<CID, UserPtr> UserMap;
167     typedef UserMap::iterator UserIter;
168 
169     typedef std::pair<std::string, bool> NickMapEntry; // the boolean being true means "save this".
170     typedef unordered_map<CID, NickMapEntry> NickMap;
171 
172     typedef unordered_multimap<CID, OnlineUser*> OnlineMap;
173     typedef OnlineMap::iterator OnlineIter;
174     typedef OnlineMap::const_iterator OnlineIterC;
175     typedef pair<OnlineIter, OnlineIter> OnlinePair;
176     typedef pair<OnlineIterC, OnlineIterC> OnlinePairC;
177 
178     Client::List clients;
179     mutable CriticalSection cs;
180 
181     UserMap users;
182     OnlineMap onlineUsers;
183     NickMap nicks;
184 
185     UserPtr me;
186 
187     Socket udp;
188 
189     CID pid;
190 
191     friend class Singleton<ClientManager>;
192 
ClientManager()193     ClientManager() {
194         TimerManager::getInstance()->addListener(this);
195     }
196 
~ClientManager()197     virtual ~ClientManager() {
198         TimerManager::getInstance()->removeListener(this);
199     }
200 
201     void updateNick(const OnlineUser& user) noexcept;
202 
203     /// @return OnlineUser* found by CID and hint; discard any user that doesn't match the hint.
findOnlineUserHint(const CID & cid,const string & hintUrl)204     OnlineUser* findOnlineUserHint(const CID& cid, const string& hintUrl) const {
205         OnlinePairC p;
206         return findOnlineUserHint(cid, hintUrl, p);
207     }
208     /**
209     * @param p OnlinePair of all the users found by CID, even those who don't match the hint.
210     * @return OnlineUser* found by CID and hint; discard any user that doesn't match the hint.
211     */
212     OnlineUser* findOnlineUserHint(const CID& cid, const string& hintUrl, OnlinePairC& p) const;
213 
getUsersFile()214     string getUsersFile() const { return Util::getPath(Util::PATH_USER_LOCAL) + "Users.xml"; }
215 
216     // ClientListener
217     virtual void on(Connected, Client* c) noexcept;
218     virtual void on(UserUpdated, Client*, const OnlineUser& user) noexcept;
219     virtual void on(UsersUpdated, Client* c, const OnlineUserList&) noexcept;
220     virtual void on(Failed, Client*, const string&) noexcept;
221     virtual void on(HubUpdated, Client* c) noexcept;
222     virtual void on(HubUserCommand, Client*, int, int, const string&, const string&) noexcept;
223     virtual void on(NmdcSearch, Client* aClient, const string& aSeeker, int aSearchType, int64_t aSize,
224         int aFileType, const string& aString) noexcept;
225     virtual void on(AdcSearch, Client* c, const AdcCommand& adc, const CID& from) noexcept;
226     // TimerManagerListener
227     virtual void on(TimerManagerListener::Minute, uint64_t aTick) noexcept;
228 };
229 
230 } // namespace dcpp
231