1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
10 //
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 //
25
26 #include <wx/tokenzr.h>
27 #include <wx/imaglist.h>
28 #include <wx/datetime.h>
29
30 #include "pixmaps/chat.ico.xpm"
31 #include "ChatSelector.h" // Interface declarations
32 #include "Preferences.h" // Needed for CPreferences
33 #include "amule.h" // Needed for theApp
34 #include "ClientRef.h" // Needed for CClientRef
35 #include "OtherFunctions.h"
36 #include "muuli_wdr.h" // Needed for amuleSpecial
37 #include "UserEvents.h"
38 #include "Constants.h" // Needed for MS_NONE
39
40 //#warning Needed while not ported
41 #include "ClientList.h"
42 #include <common/Format.h> // Needed for CFormat
43
44
45 // Default colors,
46 #define COLOR_BLACK wxTextAttr( wxColor( 0, 0, 0 ) )
47 #define COLOR_BLUE wxTextAttr( wxColor( 0, 0, 255 ) )
48 #define COLOR_GREEN wxTextAttr( wxColor( 0, 102, 0 ) )
49 #define COLOR_RED wxTextAttr( wxColor( 255, 0, 0 ) )
50
CChatSession(wxWindow * parent,wxWindowID id,const wxString & value,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator,const wxString & name)51 CChatSession::CChatSession(wxWindow* parent, wxWindowID id, const wxString& value, const wxPoint& pos, const wxSize& size, long style, const wxValidator& validator, const wxString& name)
52 : CMuleTextCtrl( parent, id, value, pos, size, style | wxTE_READONLY | wxTE_RICH | wxTE_MULTILINE, validator, name )
53 {
54 m_client_id = 0;
55 m_active = false;
56 SetBackgroundColour(*wxWHITE);
57 }
58
59
~CChatSession()60 CChatSession::~CChatSession()
61 {
62 //#warning EC NEEDED
63 #ifndef CLIENT_GUI
64 theApp->clientlist->SetChatState(m_client_id,MS_NONE);
65 #endif
66 }
67
68
AddText(const wxString & text,const wxTextAttr & style,bool newline)69 void CChatSession::AddText(const wxString& text, const wxTextAttr& style, bool newline)
70 {
71 // Split multi-line messages into individual lines
72 wxStringTokenizer tokens( text, wxT("\n") );
73
74 while ( tokens.HasMoreTokens() ) {
75 // Check if we should add a time-stamp
76 if ( GetNumberOfLines() > 1 ) {
77 // Check if the last line ended with a newline
78 wxString line = GetLineText( GetNumberOfLines() - 1 );
79 if ( line.IsEmpty() ) {
80 SetDefaultStyle( COLOR_BLACK );
81
82 AppendText( wxT(" [") + wxDateTime::Now().FormatISOTime() + wxT("] ") );
83 }
84 }
85
86 SetDefaultStyle(style);
87
88 AppendText( tokens.GetNextToken() );
89
90 // Only add newlines after the last line if it is desired
91 if ( tokens.HasMoreTokens() || newline ) {
92 AppendText( wxT("\n") );
93 }
94 }
95 }
96
97
98
99
CChatSelector(wxWindow * parent,wxWindowID id,const wxPoint & pos,wxSize siz,long style)100 CChatSelector::CChatSelector(wxWindow* parent, wxWindowID id, const wxPoint& pos, wxSize siz, long style)
101 : CMuleNotebook(parent, id, pos, siz, style)
102 {
103 wxImageList* imagelist = new wxImageList(16,16);
104
105 // Chat icon -- default state
106 imagelist->Add(wxBitmap(chat_ico_xpm));
107 // Close icon -- on mouseover
108 imagelist->Add(amuleSpecial(4));
109
110 AssignImageList(imagelist);
111 }
112
StartSession(uint64 client_id,const wxString & client_name,bool show)113 CChatSession* CChatSelector::StartSession(uint64 client_id, const wxString& client_name, bool show)
114 {
115 // Check to see if we've already opened a session for this user
116 if ( GetPageByClientID( client_id ) ) {
117 if ( show ) {
118 SetSelection( GetTabByClientID( client_id ) );
119 }
120
121 return NULL;
122 }
123
124 CChatSession* chatsession = new CChatSession(this);
125
126 chatsession->m_client_id = client_id;
127
128 wxString text;
129 text = wxT(" *** ") + (CFormat(_("Chat-Session Started: %s (%s:%u) - %s %s"))
130 % client_name
131 % Uint32toStringIP(IP_FROM_GUI_ID(client_id))
132 % PORT_FROM_GUI_ID(client_id)
133 % wxDateTime::Now().FormatISODate()
134 % wxDateTime::Now().FormatISOTime());
135
136 chatsession->AddText( text, COLOR_RED );
137 AddPage(chatsession, client_name, show, 0);
138
139 CUserEvents::ProcessEvent(CUserEvents::NewChatSession, &client_name);
140
141 return chatsession;
142 }
143
144
GetPageByClientID(uint64 client_id)145 CChatSession* CChatSelector::GetPageByClientID(uint64 client_id)
146 {
147 for ( unsigned int i = 0; i < (unsigned int ) GetPageCount(); i++ ) {
148 CChatSession* page = static_cast<CChatSession*>(GetPage(i));
149
150 if( page->m_client_id == client_id ) {
151 return page;
152 }
153 }
154
155 return NULL;
156 }
157
158
GetTabByClientID(uint64 client_id)159 int CChatSelector::GetTabByClientID(uint64 client_id)
160 {
161 for ( unsigned int i = 0; i < (unsigned int) GetPageCount(); i++ ) {
162 CChatSession* page = static_cast<CChatSession*>(GetPage(i));
163
164 if( page->m_client_id == client_id ) {
165 return i;
166 }
167 }
168
169 return -1;
170 }
171
172
ProcessMessage(uint64 sender_id,const wxString & message)173 bool CChatSelector::ProcessMessage(uint64 sender_id, const wxString& message)
174 {
175 CChatSession* session = GetPageByClientID(sender_id);
176
177 // Try to get the name (core sent it?)
178 int separator = message.Find(wxT("|"));
179 wxString client_name;
180 wxString client_message;
181 if (separator != -1) {
182 client_name = message.Left(separator);
183 client_message = message.Mid(separator+1);
184 } else {
185 // No need to define client_name. If needed, will be build on tab creation.
186 client_message = message;
187 }
188
189 bool newtab = !session;
190
191 if ( !session ) {
192 // This must be a mesage from a client that is not already chatting
193 if (client_name.IsEmpty()) {
194 // Core did not send us the name.
195 // This must NOT happen.
196 // Build a client name based on the ID
197 uint32 ip = IP_FROM_GUI_ID(sender_id);
198 client_name = CFormat(wxT("IP: %s Port: %u")) % Uint32toStringIP(ip) % PORT_FROM_GUI_ID(sender_id);
199 }
200
201 session = StartSession( sender_id, client_name, true );
202 }
203
204 // Other client connected after disconnection or a new session
205 if ( !session->m_active ) {
206 session->m_active = true;
207
208 session->AddText( _("*** Connected to Client ***"), COLOR_RED );
209 }
210
211 // Page text is client name
212 session->AddText( GetPageText(GetTabByClientID(sender_id)), COLOR_BLUE, false );
213 session->AddText( wxT(": ") + client_message, COLOR_BLACK );
214
215 return newtab;
216 }
217
SendMessage(const wxString & message,const wxString & client_name,uint64 to_id)218 bool CChatSelector::SendMessage( const wxString& message, const wxString& client_name, uint64 to_id )
219 {
220 // Dont let the user send empty messages
221 // This is also a user-fix for people who mash the enter-key ...
222 if ( message.IsEmpty() ) {
223 return false;
224 }
225
226 if (to_id) {
227 // Checks if there's a page with this client, and selects it or creates it
228 StartSession(to_id, client_name, true);
229 }
230
231 int usedtab = GetSelection();
232 // Workaround for a problem with wxNotebook, where an invalid selection is returned
233 if (usedtab >= (int)GetPageCount()) {
234 usedtab = GetPageCount() - 1;
235 }
236 if (usedtab == -1) {
237 return false;
238 }
239
240 CChatSession* ci = static_cast<CChatSession*>(GetPage(usedtab));
241
242 ci->m_active = true;
243
244 //#warning EC needed here.
245
246 #ifndef CLIENT_GUI
247 if (theApp->clientlist->SendChatMessage(ci->m_client_id, message)) {
248 ci->AddText( thePrefs::GetUserNick(), COLOR_GREEN, false );
249 ci->AddText( wxT(": ") + message, COLOR_BLACK );
250 } else {
251 ci->AddText( _("*** Connecting to Client ***"), COLOR_RED );
252 }
253 #endif
254
255 return true;
256 }
257
258 //#warning Creteil? I know you are here Creteil... follow the white rabbit.
259 /* Madcat - knock knock ...
260 ,-.,-.
261 \ \\ \
262 \ \\_\
263 / \
264 __| a a|
265 /` `'. = y)=
266 / `"`}
267 _| \ }
268 { \ ), //
269 '-', /__\ ( (
270 jgs (______)\_)_)
271 */
272
273
ConnectionResult(bool success,const wxString & message,uint64 id)274 void CChatSelector::ConnectionResult(bool success, const wxString& message, uint64 id)
275 {
276 CChatSession* ci = GetPageByClientID(id);
277 if ( !ci ) {
278 return;
279 }
280
281 if ( !success ) {
282 ci->AddText( _("*** Failed to Connect to client / Connection lost ***"), COLOR_RED );
283
284 ci->m_active = false;
285 } else {
286 // Kry - Woops, fix for the everlasting void message sending.
287 if ( !message.IsEmpty() ) {
288 ci->AddText( _("*** Connected to Client ***"), COLOR_RED );
289 ci->AddText( thePrefs::GetUserNick(), COLOR_GREEN, false );
290 ci->AddText( wxT(": ") + message, COLOR_BLACK );
291 }
292 }
293 }
294
295
EndSession(uint64 client_id)296 void CChatSelector::EndSession(uint64 client_id)
297 {
298 int usedtab;
299 if (client_id) {
300 usedtab = GetTabByClientID(client_id);
301 } else {
302 usedtab = GetSelection();
303 }
304
305 if (usedtab == -1) {
306 return;
307 }
308
309 DeletePage(usedtab);
310 }
311
312
313 // Refresh the tab assosiated with a client
RefreshFriend(uint64 toupdate_id,const wxString & new_name)314 void CChatSelector::RefreshFriend(uint64 toupdate_id, const wxString& new_name)
315 {
316 wxASSERT( toupdate_id );
317
318 int tab = GetTabByClientID(toupdate_id);
319
320 if (tab != -1) {
321 // This client has a tab.
322 SetPageText(tab,new_name);
323 } else {
324 // This client has no tab (friend disconnecting, etc)
325 // Nothing to be done here.
326 }
327 }
328
329
ShowCaptchaResult(uint64 id,bool ok)330 void CChatSelector::ShowCaptchaResult(uint64 id, bool ok)
331 {
332 CChatSession* ci = GetPageByClientID(id);
333 if (ci) {
334 ci->AddText(ok
335 ? _("*** You have passed the captcha check and the user has received your message. ***")
336 : _("*** Your response to the captcha was wrong and your message has been ignored. You can request a new captcha by sending a new message. ***"),
337 COLOR_RED );
338 }
339 }
340
341
342 #ifdef CLIENT_GUI
GetCurrentClient(CClientRef &) const343 bool CChatSelector::GetCurrentClient(CClientRef&) const
344 {
345 return false;
346 }
347 #else
GetCurrentClient(CClientRef & clientref) const348 bool CChatSelector::GetCurrentClient(CClientRef& clientref) const
349 {
350 // Get the chat session associated with the active tab
351 CChatSession* ci = static_cast<CChatSession*>(GetPage(GetSelection()));
352
353 // Get the client that the session is open to
354 if (ci) {
355 CUpDownClient * client = theApp->clientlist->FindClientByIP(IP_FROM_GUI_ID(ci->m_client_id), PORT_FROM_GUI_ID(ci->m_client_id));
356 if (client) {
357 clientref.Link(client CLIENT_DEBUGSTRING("CChatSelector::GetCurrentClient"));
358 return true;
359 }
360 }
361 return false;
362 }
363 #endif
364
365 // File_checked_for_headers
366