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
51CChatSession::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
60CChatSession::~CChatSession()
61{
62	//#warning EC NEEDED
63	#ifndef CLIENT_GUI
64	theApp->clientlist->SetChatState(m_client_id,MS_NONE);
65	#endif
66}
67
68
69void 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
100CChatSelector::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
113CChatSession* 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
145CChatSession* CChatSelector::GetPageByClientID(uint64 client_id)
146{
147	for ( unsigned int i = 0; i < (unsigned int ) GetPageCount(); i++ ) {
148		CChatSession* page = (CChatSession*)GetPage( i );
149
150		if( page->m_client_id == client_id ) {
151			return page;
152		}
153	}
154
155	return NULL;
156}
157
158
159int CChatSelector::GetTabByClientID(uint64 client_id)
160{
161	for ( unsigned int i = 0; i < (unsigned int) GetPageCount(); i++ ) {
162		CChatSession* page = (CChatSession*)GetPage( i );
163
164		if( page->m_client_id == client_id ) {
165			return i;
166		}
167	}
168
169	return -1;
170}
171
172
173bool 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
218bool 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 = (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
274void 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
296void 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
314void 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
330void 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
343bool CChatSelector::GetCurrentClient(CClientRef&) const
344{
345	return false;
346}
347#else
348bool CChatSelector::GetCurrentClient(CClientRef& clientref) const
349{
350	// Get the chat session associated with the active tab
351	CChatSession* ci = (CChatSession*)GetPage(GetSelection());
352
353	// Get the client that the session is open to
354	if (ci) {
355		clientref.Link(theApp->clientlist->FindClientByIP(IP_FROM_GUI_ID(ci->m_client_id), PORT_FROM_GUI_ID(ci->m_client_id)) CLIENT_DEBUGSTRING("CChatSelector::GetCurrentClient"));
356		return true;
357	} else {
358		return false;
359	}
360}
361#endif
362
363// File_checked_for_headers
364