1 /*
2  * This file is part of Licq, an instant messaging client for UNIX.
3  * Copyright (C) 2004-2014 Licq developers <licq-dev@googlegroups.com>
4  *
5  * Licq is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * Licq is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Licq; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #ifndef LICQMSN_MSN_H
21 #define LICQMSN_MSN_H
22 
23 #include <licq/plugin/protocolpluginhelper.h>
24 
25 #include <list>
26 #include <string>
27 #include <vector>
28 
29 #include <licq/mainloop.h>
30 #include <licq/userid.h>
31 
32 #include "msnbuffer.h"
33 #include "msnevent.h"
34 
35 namespace Licq
36 {
37 class Event;
38 class INetSocket;
39 class TCPSocket;
40 class User;
41 }
42 
43 namespace LicqMsn
44 {
45 
46 const char CONTACT_LIST[] = "FL";
47 const char ALLOW_LIST[] = "AL";
48 const char BLOCK_LIST[] = "BL";
49 
50 const unsigned short FLAG_CONTACT_LIST = 1;
51 const unsigned short FLAG_ALLOW_LIST   = 2;
52 const unsigned short FLAG_BLOCK_LIST   = 4;
53 const unsigned short FLAG_REVERSE_LIST = 8;
54 
55 #ifndef HAVE_STRNDUP
56 char *strndup(const char *s, size_t n);
57 #endif
58 
59 
60   const unsigned long MSN_DP_EVENT = 1;
61 
62 class CMSNPacket;
63 class CMSNDataEvent;
64 
65 struct SBuffer
66 {
67   CMSNBuffer *m_pBuf;
68   Licq::UserId myUserId;
69   bool m_bStored;
70 };
71 
72 typedef std::list<SBuffer *> BufferList;
73 
74 struct SStartMessage
75 {
76   CMSNPacket *m_pPacket;
77   Licq::Event* m_pEvent;
78   Licq::UserId userId;
79   unsigned long m_nSeq;
80   bool m_bConnecting,
81        m_bDataConnection;
82 };
83 
84 typedef std::list<SStartMessage*> StartList;
85 
86 struct TypingTimeout
87 {
88   int timeoutId;
89   Licq::UserId userId;
90   unsigned long convoId;
91 };
92 
93 typedef std::list<TypingTimeout> TypingTimeoutList;
94 
95 class CMSN : public Licq::ProtocolPluginHelper, public Licq::MainLoopCallback
96 {
97 public:
98   CMSN();
99   ~CMSN();
100 
101   // From Licq::PluginInterface
102   int run();
103 
104   std::string defaultServerHost() const;
105   int defaultServerPort() const;
106 
Connected()107   bool Connected() { return myServerSocket != NULL; }
108   void Logon(const Licq::UserId& ownerId, unsigned status, std::string host = std::string(), int port = 0);
109   void MSNLogoff(bool = false);
110 
111   void closeSocket(Licq::TCPSocket* sock, bool clearUser = true);
112 
113 private:
114   // From Licq::MainLoopCallback
115   void rawFileEvent(int id, int fd, int revents);
116   void socketEvent(int id, Licq::INetSocket* inetSocket, int revents);
117   void timeoutEvent(int id);
118 
119   void ProcessSignal(const Licq::ProtocolSignal* s);
120   void ProcessPipe();
121   void ProcessServerPacket(CMSNBuffer *);
122   void ProcessSSLServerPacket(CMSNBuffer &);
123   void ProcessSBPacket(const Licq::UserId& socketUserId, CMSNBuffer*,
124       Licq::TCPSocket* sock);
125 
126   // Network functions
127   void sendServerPing();
128   void SendPacket(CMSNPacket *);
129   void Send_SB_Packet(const Licq::UserId& userId, CMSNPacket* p, Licq::TCPSocket* sock,
130       bool bDelete = true);
131   void MSNAuthenticate(const std::string& host = "login.passport.com",
132       const std::string& path = "/login2.srf");
133   bool MSNSBConnectStart(const std::string& server, const std::string& cookie);
134   bool MSNSBConnectAnswer(const std::string& server, const std::string& sessionId,
135       const std::string& cookie, const Licq::UserId& userId);
136 
137   void MSNSendInvitation(const Licq::UserId& userId, CMSNPacket* _pPacket);
138   void MSNSendMessage(unsigned long eventId, const Licq::UserId& userId, const std::string& message,
139       pthread_t _tPlugin, unsigned long _nCID);
140   void MSNSendTypingNotification(const Licq::UserId& userId, unsigned long convoId);
141   void MSNChangeStatus(unsigned status);
142   void MSNAddUser(const Licq::UserId& userId);
143   void MSNRemoveUser(const Licq::UserId& userId);
144   void MSNRenameUser(const Licq::UserId& userId);
145   void MSNGrantAuth(const Licq::UserId& userId);
146   void MSNUpdateUser(const std::string& alias);
147   void MSNBlockUser(const Licq::UserId& userId);
148   void MSNUnblockUser(const Licq::UserId& userId);
149   void MSNGetDisplayPicture(const Licq::UserId& userId, const std::string& msnObject);
150 
151   // Internal functions
HashValue(int n)152   int HashValue(int n) { return n % 211; }
153   void StorePacket(SBuffer *, int);
154   void RemovePacket(const Licq::UserId& userId, int socketId, int size = 0);
155   SBuffer* RetrievePacket(const Licq::UserId& userId, int socketId);
156   Licq::Event* RetrieveEvent(unsigned long);
157   void HandlePacket(Licq::TCPSocket* sock, CMSNBuffer&, const Licq::UserId& userId);
158   unsigned long SocketToCID(int);
159   static std::string Decode(const std::string& strIn);
160   static std::string Encode(const std::string& strIn);
161   void WaitDataEvent(CMSNDataEvent *);
162   bool RemoveDataEvent(CMSNDataEvent *);
163   CMSNDataEvent* FetchDataEvent(const Licq::UserId& userId, Licq::TCPSocket* sock);
164   CMSNDataEvent* FetchStartDataEvent(const Licq::UserId& userId);
165 
166   /**
167    * Kill a conversation and all users associated with it
168    * Called when a new socket is opened to make sure it isn't associated with any old conversations
169    *
170    * @param sock Socket to clear conversations for
171    */
172   void killConversation(Licq::TCPSocket* sock);
173 
174   /**
175    * Get a unique id for scheudling a timeout callback
176    */
177   int getNextTimeoutId();
178 
179   /**
180    * Update typing status for a user
181    *
182    * @param u User object
183    * @param typing New typing status
184    * @param cid Conversation id
185    */
186   void setIsTyping(Licq::User* u, bool typing, unsigned long cid);
187 
188   /**
189    * Update our typing status towards a user
190    *
191    * @param u User object
192    * @param typing New typing status
193    * @param cid Conversation id
194    */
195   void sendIsTyping(const Licq::UserId& userId, bool typing, unsigned long cid);
196 
197   /**
198    * Handle timeouts for typing notifications
199    *
200    * @param id Timeout id from mainloop
201    */
202   void typingTimeout(int id);
203 
204   // Variables
205   Licq::UserId myOwnerId;
206   Licq::MainLoop myMainLoop;
207   Licq::TCPSocket* myServerSocket;
208   Licq::TCPSocket* mySslSocket;
209   CMSNBuffer *m_pPacketBuf,
210              *m_pSSLPacket;
211   std::vector<BufferList> m_vlPacketBucket;
212   std::list<Licq::Event*> m_pEvents;
213   std::list<CMSNDataEvent*> m_lMSNEvents;
214   StartList m_lStart;
215   bool m_bWaitingPingReply,
216        m_bCanPing;
217   TypingTimeoutList myUserTypingTimeouts;
218   TypingTimeoutList myOwnerTypingTimeouts;
219   int myNextTimeoutId;
220 
221   // Server variables
222   unsigned myStatus;
223   unsigned long m_nSessionStart;
224   std::string m_strMSPAuth,
225          m_strSID,
226          m_strKV;
227   std::string myCookie;
228   std::string myPassword;
229 
230   friend class CMSNDataEvent;
231 };
232 
233 } // namespace LicqMsn
234 
235 #endif
236