Fixed loading of zipped IP filter (#1674)
[amule.git] / src / ServerListCtrl.cpp
blobf0e560128d9b5d3b488fc7cfba62a866a8ced40c
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 "ServerListCtrl.h" // Interface declarations
28 #include <common/MenuIDs.h>
30 #include <wx/menu.h>
31 #include <wx/stattext.h>
32 #include <wx/msgdlg.h>
33 #include <wx/settings.h>
35 #include "amule.h" // Needed for theApp
36 #include "DownloadQueue.h" // Needed for CDownloadQueue
37 #ifdef ENABLE_IP2COUNTRY
38 #include "IP2Country.h" // Needed for IP2Country
39 #include "amuleDlg.h" // Needed for IP2Country
40 #endif
41 #include "ServerList.h" // Needed for CServerList
42 #include "ServerConnect.h" // Needed for CServerConnect
43 #include "Server.h" // Needed for CServer and SRV_PR_*
44 #include "Logger.h"
45 #include <common/Format.h> // Needed for CFormat
48 #define CMuleColour(x) (wxSystemSettings::GetColour(x))
51 BEGIN_EVENT_TABLE(CServerListCtrl,CMuleListCtrl)
52 EVT_LIST_ITEM_RIGHT_CLICK( -1, CServerListCtrl::OnItemRightClicked)
53 EVT_LIST_ITEM_ACTIVATED( -1, CServerListCtrl::OnItemActivated )
55 EVT_MENU( MP_PRIOLOW, CServerListCtrl::OnPriorityChange )
56 EVT_MENU( MP_PRIONORMAL, CServerListCtrl::OnPriorityChange )
57 EVT_MENU( MP_PRIOHIGH, CServerListCtrl::OnPriorityChange )
59 EVT_MENU( MP_ADDTOSTATIC, CServerListCtrl::OnStaticChange )
60 EVT_MENU( MP_REMOVEFROMSTATIC, CServerListCtrl::OnStaticChange )
62 EVT_MENU( MP_CONNECTTO, CServerListCtrl::OnConnectToServer )
64 EVT_MENU( MP_REMOVE, CServerListCtrl::OnRemoveServers )
65 EVT_MENU( MP_REMOVEALL, CServerListCtrl::OnRemoveServers )
67 EVT_MENU( MP_GETED2KLINK, CServerListCtrl::OnGetED2kURL )
69 EVT_CHAR( CServerListCtrl::OnKeyPressed )
70 END_EVENT_TABLE()
74 CServerListCtrl::CServerListCtrl( wxWindow *parent, wxWindowID winid, const wxPoint& pos, const wxSize& size,
75 long style, const wxValidator& validator, const wxString& name )
76 : CMuleListCtrl( parent, winid, pos, size, style, validator, name )
78 // Setting the sorter function.
79 SetSortFunc( SortProc );
81 // Set the table-name (for loading and saving preferences).
82 SetTableName( wxT("Server") );
84 m_connected = 0;
86 InsertColumn( COLUMN_SERVER_NAME, _("Server Name"), wxLIST_FORMAT_LEFT, 150, wxT("N") );
87 InsertColumn( COLUMN_SERVER_ADDR, _("Address"), wxLIST_FORMAT_LEFT, 140, wxT("A") );
88 InsertColumn( COLUMN_SERVER_PORT, _("Port"), wxLIST_FORMAT_LEFT, 25, wxT("P") );
89 InsertColumn( COLUMN_SERVER_DESC, _("Description"), wxLIST_FORMAT_LEFT, 150, wxT("D") );
90 InsertColumn( COLUMN_SERVER_PING, _("Ping"), wxLIST_FORMAT_LEFT, 25, wxT("p") );
91 InsertColumn( COLUMN_SERVER_USERS, _("Users"), wxLIST_FORMAT_LEFT, 40, wxT("U") );
92 InsertColumn( COLUMN_SERVER_FILES, _("Files"), wxLIST_FORMAT_LEFT, 45, wxT("F") );
93 InsertColumn( COLUMN_SERVER_PRIO, _("Priority"), wxLIST_FORMAT_LEFT, 60, wxT("r") );
94 InsertColumn( COLUMN_SERVER_FAILS, _("Failed"), wxLIST_FORMAT_LEFT, 40, wxT("f") );
95 InsertColumn( COLUMN_SERVER_STATIC, _("Static"), wxLIST_FORMAT_LEFT, 40, wxT("S") );
96 InsertColumn( COLUMN_SERVER_VERSION, _("Version"), wxLIST_FORMAT_LEFT, 80, wxT("V") );
97 #ifdef __DEBUG__
98 InsertColumn( COLUMN_SERVER_TCPFLAGS, wxT("TCP Flags"), wxLIST_FORMAT_LEFT, 80, wxT("t") );
99 InsertColumn( COLUMN_SERVER_UDPFLAGS, wxT("UDP Flags"), wxLIST_FORMAT_LEFT, 80, wxT("u") );
100 #endif
103 LoadSettings();
107 wxString CServerListCtrl::GetOldColumnOrder() const
109 return wxT("N,A,P,D,p,U,F,r,f,S,V,t,u");
113 CServerListCtrl::~CServerListCtrl()
118 void CServerListCtrl::AddServer( CServer* toadd )
120 // RefreshServer will add the server.
121 // This also means that we have simple duplicity checking. ;)
122 RefreshServer( toadd );
124 ShowServerCount();
128 void CServerListCtrl::RemoveServer(CServer* server)
130 long result = FindItem(-1, reinterpret_cast<wxUIntPtr>(server));
131 if ( result != -1 ) {
132 DeleteItem(result);
133 ShowServerCount();
138 void CServerListCtrl::RemoveAllServers(int state)
140 int pos = GetNextItem( -1, wxLIST_NEXT_ALL, state);
141 bool connected = theApp->IsConnectedED2K() ||
142 theApp->serverconnect->IsConnecting();
144 while ( pos != -1 ) {
145 CServer* server = (CServer*)GetItemData(pos);
147 if (server == m_connected && connected) {
148 wxMessageBox(_("You are connected to a server you are trying to delete. Please disconnect first. The server was NOT deleted."), _("Info"), wxOK, this);
149 ++pos;
150 } else if (server->IsStaticMember()) {
151 const wxString name = (!server->GetListName() ? wxString(_("(Unknown name)")) : server->GetListName());
153 if (wxMessageBox(CFormat(_("Are you sure you want to delete the static server %s")) % name, _("Cancel"), wxICON_QUESTION | wxYES_NO, this) == wxYES) {
154 theApp->serverlist->SetStaticServer(server, false);
155 DeleteItem( pos );
156 theApp->serverlist->RemoveServer( server );
157 } else {
158 ++pos;
160 } else {
161 DeleteItem( pos );
162 theApp->serverlist->RemoveServer( server );
165 pos = GetNextItem(pos - 1, wxLIST_NEXT_ALL, state);
168 ShowServerCount();
172 void CServerListCtrl::RefreshServer( CServer* server )
174 // Cant really refresh a NULL server
175 if (!server) {
176 return;
179 wxUIntPtr ptr = reinterpret_cast<wxUIntPtr>(server);
180 long itemnr = FindItem( -1, ptr );
181 if ( itemnr == -1 ) {
182 // We are not at the sure that the server isn't in the list, so we can re-add
183 itemnr = InsertItem( GetInsertPos( ptr ), server->GetListName() );
184 SetItemPtrData( itemnr, ptr );
186 wxListItem item;
187 item.SetId( itemnr );
188 item.SetBackgroundColour(CMuleColour(wxSYS_COLOUR_LISTBOX));
189 SetItem( item );
192 wxString serverName;
193 #ifdef ENABLE_IP2COUNTRY
194 // Get the country name
195 if (theApp->amuledlg->m_IP2Country->IsEnabled() && thePrefs::IsGeoIPEnabled()) {
196 const CountryData& countrydata = theApp->amuledlg->m_IP2Country->GetCountryData(server->GetFullIP());
197 serverName << countrydata.Name;
198 serverName << wxT(" - ");
200 #endif // ENABLE_IP2COUNTRY
201 serverName << server->GetListName();
202 SetItem(itemnr, COLUMN_SERVER_NAME, serverName);
203 SetItem(itemnr, COLUMN_SERVER_ADDR, server->GetAddress());
204 if (server->GetAuxPortsList().IsEmpty()) {
205 SetItem( itemnr, COLUMN_SERVER_PORT,
206 CFormat(wxT("%u")) % server->GetPort());
207 } else {
208 SetItem( itemnr, COLUMN_SERVER_PORT,
209 CFormat(wxT("%u (%s)")) % server->GetPort() % server->GetAuxPortsList());
211 SetItem( itemnr, COLUMN_SERVER_DESC, server->GetDescription() );
213 if ( server->GetPing() ) {
214 SetItem( itemnr, COLUMN_SERVER_PING,
215 CastSecondsToHM(server->GetPing()/1000, server->GetPing() % 1000 ) );
216 } else {
217 SetItem( itemnr, COLUMN_SERVER_PING, wxEmptyString );
220 if ( server->GetUsers() ) {
221 SetItem( itemnr, COLUMN_SERVER_USERS,
222 CFormat(wxT("%u")) % server->GetUsers());
223 } else {
224 SetItem( itemnr, COLUMN_SERVER_USERS, wxEmptyString );
227 if ( server->GetFiles() ) {
228 SetItem( itemnr, COLUMN_SERVER_FILES,
229 CFormat(wxT("%u")) % server->GetFiles());
230 } else {
231 SetItem( itemnr, COLUMN_SERVER_FILES, wxEmptyString );
234 switch ( server->GetPreferences() ) {
235 case SRV_PR_LOW: SetItem(itemnr, COLUMN_SERVER_PRIO, _("Low")); break;
236 case SRV_PR_NORMAL: SetItem(itemnr, COLUMN_SERVER_PRIO, _("Normal")); break;
237 case SRV_PR_HIGH: SetItem(itemnr, COLUMN_SERVER_PRIO, _("High") ); break;
238 default: SetItem(itemnr, COLUMN_SERVER_PRIO, wxT("---")); // this should never happen
241 SetItem( itemnr, COLUMN_SERVER_FAILS, CFormat(wxT("%u")) % server->GetFailedCount());
242 SetItem( itemnr, COLUMN_SERVER_STATIC, ( server->IsStaticMember() ? _("Yes") : _("No") ) );
243 SetItem( itemnr, COLUMN_SERVER_VERSION, server->GetVersion() );
245 #if defined(__DEBUG__) && !defined(CLIENT_GUI)
246 wxString flags;
247 /* TCP */
248 if (server->GetTCPFlags() & SRV_TCPFLG_COMPRESSION) {
249 flags += wxT("c");
251 if (server->GetTCPFlags() & SRV_TCPFLG_NEWTAGS) {
252 flags += wxT("n");
254 if (server->GetTCPFlags() & SRV_TCPFLG_UNICODE) {
255 flags += wxT("u");
257 if (server->GetTCPFlags() & SRV_TCPFLG_RELATEDSEARCH) {
258 flags += wxT("r");
260 if (server->GetTCPFlags() & SRV_TCPFLG_TYPETAGINTEGER) {
261 flags += wxT("t");
263 if (server->GetTCPFlags() & SRV_TCPFLG_LARGEFILES) {
264 flags += wxT("l");
266 if (server->GetTCPFlags() & SRV_TCPFLG_TCPOBFUSCATION) {
267 flags += wxT("o");
270 SetItem( itemnr, COLUMN_SERVER_TCPFLAGS, flags );
272 /* UDP */
273 flags.Clear();
274 if (server->GetUDPFlags() & SRV_UDPFLG_EXT_GETSOURCES) {
275 flags += wxT("g");
277 if (server->GetUDPFlags() & SRV_UDPFLG_EXT_GETFILES) {
278 flags += wxT("f");
280 if (server->GetUDPFlags() & SRV_UDPFLG_NEWTAGS) {
281 flags += wxT("n");
283 if (server->GetUDPFlags() & SRV_UDPFLG_UNICODE) {
284 flags += wxT("u");
286 if (server->GetUDPFlags() & SRV_UDPFLG_EXT_GETSOURCES2) {
287 flags += wxT("G");
289 if (server->GetUDPFlags() & SRV_UDPFLG_LARGEFILES) {
290 flags += wxT("l");
292 if (server->GetUDPFlags() & SRV_UDPFLG_UDPOBFUSCATION) {
293 flags += wxT("o");
295 if (server->GetUDPFlags() & SRV_UDPFLG_TCPOBFUSCATION) {
296 flags += wxT("O");
298 SetItem( itemnr, COLUMN_SERVER_UDPFLAGS, flags );
300 #endif
302 // Deletions of items causes rather large ammount of flicker, so to
303 // avoid this, we resort the list to ensure correct ordering.
304 if (!IsItemSorted(itemnr)) {
305 SortList();
310 void CServerListCtrl::HighlightServer( const CServer* server, bool highlight )
312 // Unset the old highlighted server if we are going to set a new one
313 if ( m_connected && highlight ) {
314 // A recursive call to do the real work.
315 HighlightServer( m_connected, false );
317 m_connected = 0;
320 long itemnr = FindItem( -1, reinterpret_cast<wxUIntPtr>(server) );
321 if ( itemnr > -1 ) {
322 wxListItem item;
323 item.SetId( itemnr );
325 if ( GetItem( item ) ) {
326 wxFont font = GetFont();
328 if ( highlight ) {
329 font.SetWeight( wxBOLD );
331 m_connected = server;
334 item.SetFont( font );
336 SetItem( item );
342 void CServerListCtrl::ShowServerCount()
344 wxStaticText* label = CastByName( wxT("serverListLabel"), GetParent(), wxStaticText );
346 if ( label ) {
347 label->SetLabel(CFormat(_("Servers (%i)")) % GetItemCount());
348 label->GetParent()->Layout();
353 void CServerListCtrl::OnItemActivated( wxListEvent& event )
355 // Unselect all items but the activated one
356 long item = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
357 while ( item > -1 ) {
358 SetItemState( item, 0, wxLIST_STATE_SELECTED);
360 item = GetNextItem( item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
363 SetItemState( event.GetIndex(), wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
365 wxCommandEvent nulEvt;
366 OnConnectToServer( nulEvt );
370 void CServerListCtrl::OnItemRightClicked(wxListEvent& event)
372 // Check if clicked item is selected. If not, unselect all and select it.
373 long index = CheckSelection(event);
375 bool enable_reconnect = false;
376 bool enable_static_on = false;
377 bool enable_static_off = false;
379 // Gather information on the selected items
380 while ( index > -1 ) {
381 CServer* server = (CServer*)GetItemData( index );
383 // The current server is selected, so we might display the reconnect option
384 if (server == m_connected) {
385 enable_reconnect = true;
388 // We want to know which options should be enabled, either one or both
389 enable_static_on |= !server->IsStaticMember();
390 enable_static_off |= server->IsStaticMember();
392 index = GetNextItem( index, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
396 wxMenu* serverMenu = new wxMenu(_("Server"));
397 wxMenu* serverPrioMenu = new wxMenu();
398 serverPrioMenu->Append( MP_PRIOLOW, _("Low") );
399 serverPrioMenu->Append( MP_PRIONORMAL, _("Normal") );
400 serverPrioMenu->Append( MP_PRIOHIGH, _("High") );
401 serverMenu->Append( MP_CONNECTTO, _("Connect to server") );
402 serverMenu->Append( 12345, _("Priority"), serverPrioMenu );
404 serverMenu->AppendSeparator();
406 if (GetSelectedItemCount() == 1) {
407 serverMenu->Append( MP_ADDTOSTATIC, _("Mark server as static") );
408 serverMenu->Append( MP_REMOVEFROMSTATIC, _("Mark server as non-static") );
409 } else {
410 serverMenu->Append( MP_ADDTOSTATIC, _("Mark servers as static") );
411 serverMenu->Append( MP_REMOVEFROMSTATIC, _("Mark servers as non-static") );
414 serverMenu->AppendSeparator();
416 if (GetSelectedItemCount() == 1) {
417 serverMenu->Append( MP_REMOVE, _("Remove server") );
418 } else {
419 serverMenu->Append( MP_REMOVE, _("Remove servers") );
421 serverMenu->Append( MP_REMOVEALL, _("Remove all servers") );
423 serverMenu->AppendSeparator();
425 if (GetSelectedItemCount() == 1) {
426 serverMenu->Append( MP_GETED2KLINK, _("Copy eD2k link to clipboard") );
427 } else {
428 serverMenu->Append( MP_GETED2KLINK, _("Copy eD2k links to clipboard") );
431 serverMenu->Enable( MP_REMOVEFROMSTATIC, enable_static_off );
432 serverMenu->Enable( MP_ADDTOSTATIC, enable_static_on );
434 if ( GetSelectedItemCount() == 1 ) {
435 if ( enable_reconnect )
436 serverMenu->SetLabel( MP_CONNECTTO, _("Reconnect to server") );
437 } else {
438 serverMenu->Enable( MP_CONNECTTO, false );
442 PopupMenu( serverMenu, event.GetPoint() );
443 delete serverMenu;
447 void CServerListCtrl::OnPriorityChange( wxCommandEvent& event )
449 uint32 priority = 0;
451 switch ( event.GetId() ) {
452 case MP_PRIOLOW: priority = SRV_PR_LOW; break;
453 case MP_PRIONORMAL: priority = SRV_PR_NORMAL; break;
454 case MP_PRIOHIGH: priority = SRV_PR_HIGH; break;
456 default:
457 return;
461 ItemDataList items = GetSelectedItems();
463 for ( unsigned int i = 0; i < items.size(); ++i ) {
464 CServer* server = (CServer*)items[ i ];
465 theApp->serverlist->SetServerPrio(server, priority);
470 void CServerListCtrl::OnStaticChange( wxCommandEvent& event )
472 bool isStatic = ( event.GetId() == MP_ADDTOSTATIC );
474 ItemDataList items = GetSelectedItems();
476 for ( unsigned int i = 0; i < items.size(); ++i ) {
477 CServer* server = (CServer*)items[ i ];
479 // Only update items that have the wrong setting
480 if ( server->IsStaticMember() != isStatic ) {
481 theApp->serverlist->SetStaticServer(server, isStatic);
487 void CServerListCtrl::OnConnectToServer( wxCommandEvent& WXUNUSED(event) )
489 int item = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
491 if ( item > -1 ) {
492 if ( theApp->IsConnectedED2K() ) {
493 theApp->serverconnect->Disconnect();
496 theApp->serverconnect->ConnectToServer( (CServer*)GetItemData( item ) );
501 void CServerListCtrl::OnGetED2kURL( wxCommandEvent& WXUNUSED(event) )
503 int pos = GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
505 wxString URL;
507 while ( pos != -1 ) {
508 CServer* server = (CServer*)GetItemData(pos);
510 URL += CFormat(wxT("ed2k://|server|%s|%d|/\n")) % server->GetFullIP() % server->GetPort();
512 pos = GetNextItem( pos, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
515 URL.RemoveLast();
517 theApp->CopyTextToClipboard( URL );
521 void CServerListCtrl::OnRemoveServers( wxCommandEvent& event )
523 if ( event.GetId() == MP_REMOVEALL ) {
524 if ( GetItemCount() ) {
525 wxString question = _("Are you sure that you wish to delete all servers?");
527 if ( wxMessageBox( question, _("Cancel"), wxICON_QUESTION | wxYES_NO, this) == wxYES ) {
528 if ( theApp->serverconnect->IsConnecting() ) {
529 theApp->downloadqueue->StopUDPRequests();
530 theApp->serverconnect->StopConnectionTry();
531 theApp->serverconnect->Disconnect();
534 RemoveAllServers(wxLIST_STATE_DONTCARE);
537 } else if ( event.GetId() == MP_REMOVE ) {
538 if ( GetSelectedItemCount() ) {
539 wxString question;
540 if (GetSelectedItemCount() == 1) {
541 question = _("Are you sure that you wish to delete the selected server?");
542 } else {
543 question = _("Are you sure that you wish to delete the selected servers?");
546 if ( wxMessageBox( question, _("Cancel"), wxICON_QUESTION | wxYES_NO, this) == wxYES ) {
547 RemoveAllServers(wxLIST_STATE_SELECTED);
554 void CServerListCtrl::OnKeyPressed( wxKeyEvent& event )
556 // Check if delete was pressed
557 if ((event.GetKeyCode() == WXK_DELETE) || (event.GetKeyCode() == WXK_NUMPAD_DELETE)) {
558 wxCommandEvent evt;
559 evt.SetId( MP_REMOVE );
560 OnRemoveServers( evt );
561 } else {
562 event.Skip();
567 int CServerListCtrl::SortProc(wxUIntPtr item1, wxUIntPtr item2, long sortData)
569 CServer* server1 = (CServer*)item1;
570 CServer* server2 = (CServer*)item2;
572 int mode = (sortData & CMuleListCtrl::SORT_DES) ? -1 : 1;
574 switch (sortData & CMuleListCtrl::COLUMN_MASK) {
575 // Sort by server-name
576 case COLUMN_SERVER_NAME:
577 return mode * server1->GetListName().CmpNoCase(server2->GetListName());
579 // Sort by address
580 case COLUMN_SERVER_ADDR:
582 if ( server1->HasDynIP() && server2->HasDynIP()) {
583 return mode * server1->GetDynIP().CmpNoCase( server2->GetDynIP() );
584 } else if (server1->HasDynIP()) {
585 return mode * -1;
586 } else if (server2->HasDynIP()) {
587 return mode * 1;
588 } else {
589 uint32 a = wxUINT32_SWAP_ALWAYS(server1->GetIP());
590 uint32 b = wxUINT32_SWAP_ALWAYS(server2->GetIP());
591 return mode * CmpAny(a, b);
594 // Sort by port
595 case COLUMN_SERVER_PORT: return mode * CmpAny( server1->GetPort(), server2->GetPort() );
596 // Sort by description
597 case COLUMN_SERVER_DESC: return mode * server1->GetDescription().CmpNoCase( server2->GetDescription() );
598 // Sort by Ping
599 // The -1 ensures that a value of zero (no ping known) is sorted last.
600 case COLUMN_SERVER_PING: return mode * CmpAny( server1->GetPing() - 1, server2->GetPing() -1 );
601 // Sort by user-count
602 case COLUMN_SERVER_USERS: return mode * CmpAny( server1->GetUsers(), server2->GetUsers() );
603 // Sort by file-count
604 case COLUMN_SERVER_FILES: return mode * CmpAny( server1->GetFiles(), server2->GetFiles() );
605 // Sort by priority
606 case COLUMN_SERVER_PRIO:
608 uint32 srv_pr1 = server1->GetPreferences();
609 uint32 srv_pr2 = server2->GetPreferences();
610 switch ( srv_pr1 ) {
611 case SRV_PR_HIGH: srv_pr1 = SRV_PR_MAX; break;
612 case SRV_PR_NORMAL: srv_pr1 = SRV_PR_MID; break;
613 case SRV_PR_LOW: srv_pr1 = SRV_PR_MIN; break;
614 default: return 0;
616 switch ( srv_pr2 ) {
617 case SRV_PR_HIGH: srv_pr2 = SRV_PR_MAX; break;
618 case SRV_PR_NORMAL: srv_pr2 = SRV_PR_MID; break;
619 case SRV_PR_LOW: srv_pr2 = SRV_PR_MIN; break;
620 default: return 0;
622 return mode * CmpAny( srv_pr1, srv_pr2 );
624 // Sort by failure-count
625 case COLUMN_SERVER_FAILS: return mode * CmpAny( server1->GetFailedCount(), server2->GetFailedCount() );
626 // Sort by static servers
627 case COLUMN_SERVER_STATIC:
629 return mode * CmpAny( server2->IsStaticMember(), server1->IsStaticMember() );
631 // Sort by version
632 case COLUMN_SERVER_VERSION: return mode * FuzzyStrCmp(server1->GetVersion(), server2->GetVersion());
634 default:
635 return 0;
638 // File_checked_for_headers