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