1 /**
2  * libICQ2000 Client header
3  *
4  * Copyright (C) 2001 Barnaby Gray <barnaby@beedesign.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
19  *
20  */
21 
22 #ifndef CLIENT_H
23 #define CLIENT_H
24 
25 #include <iostream>
26 #include <string>
27 
28 #include <map>
29 #include <queue>
30 
31 #include <libicq2000/sigslot.h>
32 
33 #include <time.h>
34 
35 #include <libicq2000/events.h>
36 #include <libicq2000/constants.h>
37 #include <libicq2000/Contact.h>
38 #include <libicq2000/ContactTree.h>
39 #include <libicq2000/ContactList.h>
40 #include <libicq2000/userinfoconstants.h>
41 
42 namespace ICQ2000
43 {
44 
45   /* predeclare classes */
46   class MessageSNAC;
47   class MessageACKSNAC;
48   class MessageOfflineUserSNAC;
49   class MessageTypingNotificationSNAC;
50   class SrvResponseSNAC;
51   class UINResponseSNAC;
52   class RateInfoChangeSNAC;
53   class BuddyOnlineSNAC;
54   class BuddyOfflineSNAC;
55   class UserInfoSNAC;
56   class OutSNAC;
57   class DirectClient;
58   class DCCache;
59   class MessageHandler;
60   class RequestIDCache;
61   class RequestIDCacheValue;
62   class ICBMCookieCache;
63   class SMTPClient;
64   class SocketClient;
65   class Buffer;
66   class TCPSocket;
67   class TCPServer;
68   class Translator;
69   class FileTransferClient;
70   class FTCache;
71   class SBLListSNAC;
72 
73   /**
74    *  The main library object.  This is the object the user interface
75    *  instantiates for a connection, hooks up to signal on and has the
76    *  methods to connect, disconnect and send events from.
77    */
78   class Client : public sigslot::has_slots<>
79   {
80    private:
81     enum State { NOT_CONNECTED,
82 		 AUTH_AWAITING_CONN_ACK,
83 		 AUTH_AWAITING_AUTH_REPLY,
84 		 BOS_AWAITING_CONN_ACK,
85 		 BOS_AWAITING_LOGIN_REPLY,
86 		 BOS_LOGGED_IN,
87 		 UIN_AWAITING_CONN_ACK,
88 		 UIN_AWAITING_UIN_REPLY
89     } m_state;
90 
91     enum Sbl_op { USER_ADD,
92     	USER_REMOVE,
93     	GROUP_ADD,
94     	GROUP_REMOVE
95     };
96 
97     struct Sbl_edit {
98     	Sbl_op operation;
99     	Sbl_item item;
100     };
101 
102     unsigned short get_random_buddy_id();
103     void processSblEdits();
104 
105     std::deque<Sbl_edit> m_sbl_edits; // edits on m_sbl_*
106     std::map<unsigned int, Sbl_item> m_sbl_map;  // uin:info
107     std::map<std::string, Sbl_group> m_sbl_groups; // name:info
108     std::map<unsigned short, std::string> m_sbl_groupnames; // group_id::group_name
109     std::set<unsigned short> m_sbl_tags; // used tag ids
110     bool m_sbl_canedit; // local SBL is ready, I can do edits on it
111     unsigned short m_sbl_privacy_id; // privacy buddy ID
112 
113     ContactRef m_self;
114     std::string m_password;
115     Status m_status_wanted;
116     bool m_invisible_wanted;
117     bool m_web_aware;
118     unsigned short m_random_group;
119 
120     std::string m_authorizerHostname;
121     unsigned short m_authorizerPort;
122 
123     std::string m_bosHostname;
124     unsigned short m_bosPort;
125     bool m_bosOverridePort;
126 
127     std::string m_client_bind_host;
128 
129     bool m_in_dc, m_out_dc;
130 
131     unsigned short m_client_seq_num;
132     unsigned int m_requestid;
133 
134     Translator * m_translator;
135 
136     ContactTree m_contact_tree;
137 
138     ContactList m_visible_list;
139     ContactList m_invisible_list;
140 
141     bool m_fetch_sbl;
142 
143     bool m_sbl_inedit;
144     std::deque<OutSNAC*> sblSNACs;
145 
146     MessageHandler * m_message_handler;
147 
148     unsigned char *m_cookie_data;
149     unsigned short m_cookie_length;
150 
151     unsigned int m_ext_ip;
152     bool m_use_portrange;
153     bool m_use_typing_notif;
154     unsigned short m_upper_port, m_lower_port;
155     TCPSocket * m_serverSocket;
156     TCPServer * m_listenServer;
157 
158     SMTPClient * m_smtp;
159 
160     DCCache * m_dccache;
161     FTCache * m_ftcache;
162 
163     time_t m_last_server_ping;
164 
165     RequestIDCache * m_reqidcache;
166     ICBMCookieCache * m_cookiecache;
167 
168     Buffer * m_recv;
169 
170     void Init();
171     unsigned short NextSeqNum();
172     unsigned int NextRequestID();
173 
174     void ConnectAuthorizer(State state);
175     void DisconnectAuthorizer();
176     void ConnectBOS();
177     void DisconnectBOS();
178 
179     // -- Ping server --
180     void PingServer();
181 
182     DirectClient* ConnectDirect(const ContactRef& c);
183     void DisconnectDirectConns();
184     void DisconnectDirectConn(int fd);
185 
186     // ------------------ Signal dispatchers -----------------
187     void SignalConnect();
188     void SignalDisconnect(DisconnectedEvent::Reason r);
189     void SignalMessage(MessageSNAC *snac);
190     void SignalMessageACK(MessageACKSNAC *snac);
191     void SignalMessageOfflineUser(MessageOfflineUserSNAC *snac);
192     void SignalTypingNotification(MessageTypingNotificationSNAC *snac);
193     void SignalSrvResponse(SrvResponseSNAC *snac);
194     void SignalUINResponse(UINResponseSNAC *snac);
195     void SignalUINRequestError();
196     void SignalRateInfoChange(RateInfoChangeSNAC *snac);
197     void SignalLog(LogEvent::LogType type, const std::string& msg);
198     void SignalUserOnline(BuddyOnlineSNAC *snac);
199     void SignalUserOffline(BuddyOfflineSNAC *snac);
200     void SignalAddSocket(int fd, SocketEvent::Mode m);
201     void SignalRemoveSocket(int fd);
202     // ------------------ Outgoing packets -------------------
203 
204     // -------------- Callbacks from ContactList -------------
205     void contactlist_cb(ContactListEvent *ev);
206 
207     // ------- Callbacks from visible, invisible lists -------
208     void visiblelist_cb(ContactListEvent *ev);
209     void invisiblelist_cb(ContactListEvent *ev);
210 
211     // -------------- Callbacks from Contacts ----------------
212 
213     void SendAuthReq();
214     void SendNewUINReq();
215     void SendCookie();
216     void SendCapabilities();
217     void SendRateInfoRequest();
218     void SendRateInfoAck();
219     void SendPersonalInfoRequest();
220     void SendAddICBMParameter();
221     void SendSetUserInfo();
222     void SendLogin();
223     void SendRequestSBL();
224     void SendSBLReceivedACK();
225     void SendOfflineMessagesACK();
226 
227     void SendAdvancedACK(MessageSNAC *snac);
228 
229     void Send(Buffer& b);
230 
231     void HandleUserInfoSNAC(UserInfoSNAC *snac);
232 
233     void FLAPwrapSNAC(Buffer& b, const OutSNAC& snac);
234     void FLAPwrapSNACandSend(const OutSNAC& snac);
235 
236     // ------------------ Incoming packets -------------------
237 
238     /**
239      *  non-blocking receives all waiting packets from server
240      *  and parses and handles them
241      */
242     void RecvFromServer();
243 
244     void Parse();
245     void ParseCh1(Buffer& b, unsigned short seq_num);
246     void ParseCh2(Buffer& b, unsigned short seq_num);
247     void ParseCh3(Buffer& b, unsigned short seq_num);
248     void ParseCh4(Buffer& b, unsigned short seq_num);
249 
250     // -------------------------------------------------------
251 
252     ContactRef getUserInfoCacheContact(unsigned int reqid);
253 
254 	void fillSBLMap(SBLListSNAC *sbl);
255     void mergeSBL(ContactTree& tree);
256 
257     void SendSBLAuthReq(AuthReqEvent *ev);
258     void SendSBLAuthReply(AuthAckEvent *ev);
259 
260     void ICBMCookieCache_expired_cb(MessageEvent *ev);
261     void dccache_expired_cb(DirectClient *dc);
262     void ftcache_expired_cb(FileTransferClient *ftc);
263     void reqidcache_expired_cb( RequestIDCacheValue *v );
264     void dc_connected_cb(SocketClient *dc);
265     void dc_log_cb(LogEvent *ev);
266     void dc_socket_cb(SocketEvent *ev);
267     void dc_messageack_cb(MessageEvent *ev);
268     void ftc_messageack_cb(MessageEvent *ev);
269 
270     bool SendDirect(MessageEvent *ev);
271 
272     void SendViaServer(MessageEvent *ev);
273     void SendViaServerAdvanced(MessageEvent *ev);
274     void SendViaServerNormal(MessageEvent *ev);
275 
276     void Disconnect(DisconnectedEvent::Reason r = DisconnectedEvent::REQUESTED);
277 
278    public:
279     Client();
280     Client(const unsigned int uin, const std::string& password);
281     ~Client();
282 
283     void setUIN(unsigned int uin);
284     unsigned int getUIN() const;
285     void setPassword(const std::string& password);
286     std::string getPassword() const;
287 
288     ContactRef getSelfContact();
289 
290     bool setTranslationMap(const std::string& szMapFileName);
291     const std::string& getTranslationMapFileName() const;
292     const std::string& getTranslationMapName() const;
293     bool usingDefaultMap() const;
294 
295     // -- Signals --
296     /**
297      *  The signal to connect to for listening to ConnectingEvent's.
298      *  A ConnectingEvent is signalled when the client is trying to go online.
299      * @see connected, ConnectingEvent
300      */
301     sigslot::signal1<ConnectingEvent*> connecting;
302 
303     /**
304      *  The signal to connect to for listening to ConnectedEvent's.
305      *  A ConnectedEvent is signalled when the client is online proper.
306      * @see disconnected, ConnectedEvent
307      */
308     sigslot::signal1<ConnectedEvent*> connected;
309 
310     sigslot::signal1<SBLReceivedEvent*> sbl_received;
311 
312     /**
313      *  The signal to connect to for listening to DisconnectedEvent's.
314      *  A DisconnectedEvent is signalled when you were disconnected
315      *  from the server.  This could have been because it was
316      *  requested, or the server might have chucked you off. More
317      *  information can be in the DisconnectedEvent.
318      *
319      *  DisconnectedEvent's don't necessarily match a ConnectedEvent,
320      *  if you try connecting with an incorrect password, you will
321      *  never get a ConnectedEvent before the DisconnectedEvent
322      *  signalling incorrect password.
323      * @see connected, DisconnectedEvent
324      */
325     sigslot::signal1<DisconnectedEvent*> disconnected;
326 
327     /**
328      *  The signal to connect to for listening to incoming
329      *  MessageEvent. This includes far more than just messages.
330      * @see MessageEvent
331      */
332     sigslot::signal1<MessageEvent*> messaged;
333 
334     /**
335      *  The signal to connect to for listening to the acknowledgements
336      *  that the library will generate for when the remote client
337      *  sends back a message ack. Additionally it will it is used for
338      *  signalling to the Client message delivery failures and when
339      *  messages are being reattempted to be send through the server.
340      * @see messaged, MessageEvent
341      */
342     sigslot::signal1<MessageEvent*> messageack;
343 
344     /**
345      *  The signal to connect to for listening to Contact list events.
346      * @see ContactListEvent
347      */
348     sigslot::signal1<ContactListEvent*> contactlist;
349 
350     /**
351      *  The signal to connect to for listening for Contact Userinfo events.
352      * @see UserInfoChangeEvent
353      */
354     sigslot::signal1<UserInfoChangeEvent*> contact_userinfo_change_signal;
355 
356     /**
357      *  The signal to connect to for listening for Contact Status change events.
358      * @see StatusChangeEvent
359      */
360     sigslot::signal1<StatusChangeEvent*> contact_status_change_signal;
361 
362     /**
363      *  The signal to connect to for listening for Contact Typing Notification events.
364      * @see UserTypingNotificationEvent
365      */
366     sigslot::signal1<UserTypingNotificationEvent*> contact_typing_signal;
367 
368     /**
369      *  The signal for when registering a new UIN has succeeded or
370      *  failed after a call to RegisterUIN().
371      * @see NewUINEvent, RegisterUIN
372      */
373     sigslot::signal1<NewUINEvent*> newuin;
374 
375     /**
376      *  The signal for when the server signals the rate at which the client
377      *  is sending has been changed.
378      * @see RateInfoChangeEvent
379      */
380     sigslot::signal1<RateInfoChangeEvent*> rate;
381 
382     /**
383      *  The signal for all logging messages that are passed back to
384      *  the client.  This leads to a very flexible logging system, as
385      *  the user interface may decide where to write the log message
386      *  to (stdout, a dialog box, etc..) and also may pick which type
387      *  of log messages to display and which to ignore.
388      * @see LogEvent
389      */
390     sigslot::signal1<LogEvent*> logger;
391 
392     /**
393      *  The signal for socket events. All clients must listen to this
394      *  and implement their particular scheme of blocking on multiple
395      *  sockets for read/write/exception, usually the select system
396      *  call in someway. Often toolkits will hide all the details of
397      *  select inside them, such as the way gtk or gtkmm do.
398      *
399      * @see SocketEvent
400      */
401     sigslot::signal1<SocketEvent*> socket;
402 
403     /**
404      *  The signal to connect to for listening for Self Contact Userinfo events.
405      * @see UserInfoChangeEvent
406      */
407     sigslot::signal1<UserInfoChangeEvent*> self_contact_userinfo_change_signal;
408 
409     /**
410      *  The signal to connect to for listening for Self Contact Status change events.
411      * @see StatusChangeEvent
412      */
413     sigslot::signal1<StatusChangeEvent*> self_contact_status_change_signal;
414 
415     /**
416      *  Signal when someone requests your away message. The client
417      *  should setMessage in the AutoMessageEvent to what your away
418      *  message is. This allows dynamic away messages for different
419      *  people.
420      */
421     sigslot::signal1<ICQMessageEvent*> want_auto_resp;
422 
423     /**
424      *  Signal when a Search Result has been updated.  The last signal
425      *  on a search result will be with
426      *  SearchResultEvent::isFinished() set to true. After this the
427      *  event is finished and deleted from memory by the library.
428      */
429     sigslot::signal1<SearchResultEvent*> search_result;
430 
431     /**
432      *  Signal when an incoming file transfer request is received.
433      */
434     sigslot::signal1<FileTransferEvent*> filetransfer_incoming_signal;
435 
436     /**
437      *  Signal when a FileTransferEvent object is updated.
438      */
439     sigslot::signal1<FileTransferEvent*> filetransfer_update_signal;
440 
441     // -------------
442 
443     // -- Send calls --
444     void SendEvent(MessageEvent *ev);
445 
446     // -- File Transfer methods --
447     void SendFileTransfer(FileTransferEvent *ev);
448     void SendFileTransferACK(FileTransferEvent *ev);
449     void CancelFileTransfer(FileTransferEvent *ev);
450 
451     // -- Set Status --
452     void setStatus(const Status st);
453     void setStatus(const Status st, bool inv);
454     void setInvisible(bool inv);
455     void setWebAware(bool wa);
456     void setRandomChatGroup(unsigned short group);
457 
458     Status getStatus() const;
459     bool getInvisible() const;
460 
461     Status getStatusWanted() const;
462     bool getInvisibleWanted() const;
463 
464     bool getWebAware() const;
465 
466     void uploadSelfDetails();
467 
468     void uploadServerBasedContact(const ContactRef& c);
469     void uploadServerBasedGroup(const ContactTree::Group& gp);
470     void uploadServerBasedContactList();
471 
472     void updateServerBasedContact(const ContactRef& c);
473 
474     void removeServerBasedContact(const ContactRef& c);
475     void removeServerBasedGroup(const ContactTree::Group& gp);
476     void removeServerBasedContactList();
477 
478     // -- Contact List --
479     void addVisible(ContactRef c);
480     void removeVisible(const unsigned int uin);
481     void addInvisible(ContactRef c);
482     void removeInvisible(const unsigned int uin);
483     ContactRef getContact(const unsigned int uin);
484 
485     ContactTree& getContactTree();
486 
487     void fetchSimpleContactInfo(ContactRef c);
488     void fetchDetailContactInfo(ContactRef c);
489     void fetchServerBasedContactList();
490     void fetchServerBasedContactList(int); // the conditional form - TODO!
491     void fetchSelfSimpleContactInfo();
492     void fetchSelfDetailContactInfo();
493 
494     void SendSBLSNAC(OutSNAC *sn);  // send SBL SNAC
495     void upgradeToSBL();  // save local contact to SBL
496 
497     // -- Whitepage searches --
498     SearchResultEvent* searchForContacts(const std::string& nickname, const std::string& firstname,
499 					 const std::string& lastname);
500 
501     SearchResultEvent* searchForContacts(const std::string& nickname, const std::string& firstname,
502 					 const std::string& lastname, const std::string& email,
503 					 AgeRange age, Sex sex, unsigned char language, const std::string& city,
504 					 const std::string& state, unsigned short country,
505 					 const std::string& company_name, const std::string& department,
506 					 const std::string& position, bool only_online);
507 
508     SearchResultEvent* searchForContacts(unsigned int uin);
509 
510     SearchResultEvent* searchForContacts(const std::string& keyword);
511 
512     SearchResultEvent* searchForContacts(RandomChatGroup group);
513 
514     /*
515      *  Poll must be called regularly (at least every 60 seconds)
516      *  but I recommended 5 seconds, so timeouts work with good
517      *  granularity.
518      *  It is not related to the socket callback - the client using
519      *  this library must select() on the sockets it gets signalled
520      *  and call socket_cb when select returns a status flag on one
521      *  of the sockets. ickle simply uses the gtk-- built in signal handlers
522      *  to do all this.
523      */
524 
525     // -- Network settings --
526     void setLoginServerHost(const std::string& host);
527     std::string getLoginServerHost() const;
528 
529     void setLoginServerPort(const unsigned short& port);
530     unsigned short getLoginServerPort() const;
531 
532     void setBOSServerOverridePort(const bool& b);
533     bool getBOSServerOverridePort() const;
534 
535     void setBOSServerPort(const unsigned short& port);
536     unsigned short getBOSServerPort() const;
537 
538     void setSMTPServerHost(const std::string& host);
539     std::string getSMTPServerHost() const;
540 
541     void setSMTPServerPort(unsigned short port);
542     unsigned short getSMTPServerPort() const;
543 
544     void setAcceptInDC(bool d);
545     bool getAcceptInDC() const;
546 
547     void setUseOutDC(bool d);
548     bool getUseOutDC() const;
549 
550     void setPortRangeLowerBound(unsigned short lower);
551     void setPortRangeUpperBound(unsigned short upper);
552     unsigned short getPortRangeLowerBound() const;
553     unsigned short getPortRangeUpperBound() const;
554 
555     void setUsePortRange(bool b);
556     bool getUsePortRange() const;
557 
558     void setClientBindHost(const std::string& host);
559     std::string getClientBindHost() const;
560 
561     void setTypingNotifications(bool b);
562 
563     void Poll();
564     void socket_cb(int fd, SocketEvent::Mode m);
565 
566     void RegisterUIN();
567 
568     /* isConnected() is a convenience for the
569      * client, it should correspond exactly to ConnectedEvents
570      * & DisconnectedEvents the client gets
571      */
572     bool isConnected() const;
573 
574     void set_translator(Translator * t);
575   };
576 }
577 
578 #endif
579