Workaround for crash on closing the last search tab
[amule.git] / src / ChatSelector.cpp
blobff6935d46ebfe74b30ff6f0827c8ebb429e09e3c
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.
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.
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.
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
26 #include <wx/tokenzr.h>
27 #include <wx/imaglist.h>
28 #include <wx/datetime.h>
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
40 //#warning Needed while not ported
41 #include "ClientList.h"
42 #include <common/Format.h> // Needed for CFormat
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 ) )
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 )
54 m_client_id = 0;
55 m_active = false;
56 SetBackgroundColour(*wxWHITE);
60 CChatSession::~CChatSession()
62 //#warning EC NEEDED
63 #ifndef CLIENT_GUI
64 theApp->clientlist->SetChatState(m_client_id,MS_NONE);
65 #endif
69 void CChatSession::AddText(const wxString& text, const wxTextAttr& style, bool newline)
71 // Split multi-line messages into individual lines
72 wxStringTokenizer tokens( text, wxT("\n") );
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 );
82 AppendText( wxT(" [") + wxDateTime::Now().FormatISOTime() + wxT("] ") );
86 SetDefaultStyle(style);
88 AppendText( tokens.GetNextToken() );
90 // Only add newlines after the last line if it is desired
91 if ( tokens.HasMoreTokens() || newline ) {
92 AppendText( wxT("\n") );
100 CChatSelector::CChatSelector(wxWindow* parent, wxWindowID id, const wxPoint& pos, wxSize siz, long style)
101 : CMuleNotebook(parent, id, pos, siz, style)
103 wxImageList* imagelist = new wxImageList(16,16);
105 // Chat icon -- default state
106 imagelist->Add(wxBitmap(chat_ico_xpm));
107 // Close icon -- on mouseover
108 imagelist->Add(amuleSpecial(4));
110 AssignImageList(imagelist);
113 CChatSession* CChatSelector::StartSession(uint64 client_id, const wxString& client_name, bool show)
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 ) );
121 return NULL;
124 CChatSession* chatsession = new CChatSession(this);
126 chatsession->m_client_id = client_id;
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());
136 chatsession->AddText( text, COLOR_RED );
137 AddPage(chatsession, client_name, show, 0);
139 CUserEvents::ProcessEvent(CUserEvents::NewChatSession, &client_name);
141 return chatsession;
145 CChatSession* CChatSelector::GetPageByClientID(uint64 client_id)
147 for ( unsigned int i = 0; i < (unsigned int ) GetPageCount(); i++ ) {
148 CChatSession* page = static_cast<CChatSession*>(GetPage(i));
150 if( page->m_client_id == client_id ) {
151 return page;
155 return NULL;
159 int CChatSelector::GetTabByClientID(uint64 client_id)
161 for ( unsigned int i = 0; i < (unsigned int) GetPageCount(); i++ ) {
162 CChatSession* page = static_cast<CChatSession*>(GetPage(i));
164 if( page->m_client_id == client_id ) {
165 return i;
169 return -1;
173 bool CChatSelector::ProcessMessage(uint64 sender_id, const wxString& message)
175 CChatSession* session = GetPageByClientID(sender_id);
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;
189 bool newtab = !session;
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);
201 session = StartSession( sender_id, client_name, true );
204 // Other client connected after disconnection or a new session
205 if ( !session->m_active ) {
206 session->m_active = true;
208 session->AddText( _("*** Connected to Client ***"), COLOR_RED );
211 // Page text is client name
212 session->AddText( GetPageText(GetTabByClientID(sender_id)), COLOR_BLUE, false );
213 session->AddText( wxT(": ") + client_message, COLOR_BLACK );
215 return newtab;
218 bool CChatSelector::SendMessage( const wxString& message, const wxString& client_name, uint64 to_id )
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;
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);
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;
236 if (usedtab == -1) {
237 return false;
240 CChatSession* ci = static_cast<CChatSession*>(GetPage(usedtab));
242 ci->m_active = true;
244 //#warning EC needed here.
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 );
253 #endif
255 return true;
258 //#warning Creteil? I know you are here Creteil... follow the white rabbit.
259 /* Madcat - knock knock ...
260 ,-.,-.
261 \ \\ \
262 \ \\_\
264 __| a a|
265 /` `'. = y)=
266 / `"`}
267 _| \ }
268 { \ ), //
269 '-', /__\ ( (
270 jgs (______)\_)_)
274 void CChatSelector::ConnectionResult(bool success, const wxString& message, uint64 id)
276 CChatSession* ci = GetPageByClientID(id);
277 if ( !ci ) {
278 return;
281 if ( !success ) {
282 ci->AddText( _("*** Failed to Connect to client / Connection lost ***"), COLOR_RED );
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 );
296 void CChatSelector::EndSession(uint64 client_id)
298 int usedtab;
299 if (client_id) {
300 usedtab = GetTabByClientID(client_id);
301 } else {
302 usedtab = GetSelection();
305 if (usedtab == -1) {
306 return;
309 DeletePage(usedtab);
313 // Refresh the tab assosiated with a client
314 void CChatSelector::RefreshFriend(uint64 toupdate_id, const wxString& new_name)
316 wxASSERT( toupdate_id );
318 int tab = GetTabByClientID(toupdate_id);
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.
330 void CChatSelector::ShowCaptchaResult(uint64 id, bool ok)
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 );
342 #ifdef CLIENT_GUI
343 bool CChatSelector::GetCurrentClient(CClientRef&) const
345 return false;
347 #else
348 bool CChatSelector::GetCurrentClient(CClientRef& clientref) const
350 // Get the chat session associated with the active tab
351 CChatSession* ci = static_cast<CChatSession*>(GetPage(GetSelection()));
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;
361 return false;
363 #endif
365 // File_checked_for_headers