1//
2// This file is part of the aMule Project.
3//
4// Copyright (c) 2004-2011 Marcelo Roberto Jimenez ( phoenix@amule.org )
5// Copyright (c) 2006-2011 aMule Team ( admin@amule.org / http://www.amule.org )
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
27//
28// Country flags are from FAMFAMFAM (http://www.famfamfam.com)
29//
30// Flag icons - http://www.famfamfam.com
31//
32// These icons are public domain, and as such are free for any use (attribution appreciated but not required).
33//
34// Note that these flags are named using the ISO3166-1 alpha-2 country codes where appropriate.
35// A list of codes can be found at http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
36//
37// If you find these icons useful, please donate via paypal to mjames@gmail.com
38// (or click the donate button available at http://www.famfamfam.com/lab/icons/silk)
39//
40// Contact: mjames@gmail.com
41//
42
43#ifdef HAVE_CONFIG_H
44#	include "config.h"		// Needed for ENABLE_IP2COUNTRY
45#endif
46
47#ifdef _MSC_VER
48// For MSVC we need to check here if geoip is available at all. MinGW needs the include below however.
49
50// Block unnecessary includes from GeoIP.h
51#define _WINDOWS_
52#define _WINSOCK2API_
53#define _WS2TCPIP_H_
54#define _WSPIAPI_H_
55#include <GeoIP.h>
56#endif
57
58#ifdef ENABLE_IP2COUNTRY
59
60#include "Preferences.h"	// For thePrefs
61#include "CFile.h"			// For CPath
62#include "HTTPDownload.h"
63#include "Logger.h"			// For AddLogLineM()
64#include <common/Format.h>		// For CFormat()
65#include "common/FileFunctions.h"	// For UnpackArchive
66#include <common/StringFunctions.h>	// For unicode2char()
67#include "pixmaps/flags_xpm/CountryFlags.h"
68
69#include <wx/intl.h>
70#include <wx/image.h>
71
72#include <GeoIP.h>
73#include "IP2Country.h"
74
75CIP2Country::CIP2Country(const wxString& configDir)
76{
77	m_geoip = NULL;
78	m_DataBaseName = wxT("GeoIP.dat");
79	m_DataBasePath = configDir + m_DataBaseName;
80}
81
82void CIP2Country::Enable()
83{
84	Disable();
85
86	if (m_CountryDataMap.empty()) {
87		LoadFlags();
88	}
89
90	if (!CPath::FileExists(m_DataBasePath)) {
91		Update();
92		return;
93	}
94
95	m_geoip = GeoIP_open(unicode2char(m_DataBasePath), GEOIP_STANDARD);
96}
97
98void CIP2Country::Update()
99{
100	AddLogLineN(CFormat(_("Download new GeoIP.dat from %s")) % thePrefs::GetGeoIPUpdateUrl());
101	CHTTPDownloadThread *downloader = new CHTTPDownloadThread(thePrefs::GetGeoIPUpdateUrl(), m_DataBasePath + wxT(".download"), m_DataBasePath, HTTP_GeoIP, true, true);
102	downloader->Create();
103	downloader->Run();
104}
105
106void CIP2Country::Disable()
107{
108	if (m_geoip) {
109		GeoIP_delete(m_geoip);
110		m_geoip = NULL;
111	}
112}
113
114void CIP2Country::DownloadFinished(uint32 result)
115{
116	if (result == HTTP_Success) {
117		Disable();
118		// download succeeded. Switch over to new database.
119		wxString newDat = m_DataBasePath + wxT(".download");
120
121		// Try to unpack the file, might be an archive
122		const wxChar* geoip_files[] = {
123			m_DataBaseName,
124			NULL
125		};
126
127		if (UnpackArchive(CPath(newDat), geoip_files).second == EFT_Error) {
128			AddLogLineC(_("Download of GeoIP.dat file failed, aborting update."));
129			return;
130		}
131
132		if (wxFileExists(m_DataBasePath)) {
133			if (!wxRemoveFile(m_DataBasePath)) {
134				AddLogLineC(CFormat(_("Failed to remove %s file, aborting update.")) % m_DataBaseName);
135				return;
136			}
137		}
138
139		if (!wxRenameFile(newDat, m_DataBasePath)) {
140			AddLogLineC(CFormat(_("Failed to rename %s file, aborting update.")) % m_DataBaseName);
141			return;
142		}
143
144		Enable();
145		if (m_geoip) {
146			AddLogLineN(CFormat(_("Successfully updated %s")) % m_DataBaseName);
147		} else {
148			AddLogLineC(_("Error updating GeoIP.dat"));
149		}
150 	} else if (result == HTTP_Skipped) {
151 		AddLogLineN(CFormat(_("Skipped download of %s, because requested file is not newer.")) % m_DataBaseName);
152	} else {
153		AddLogLineC(CFormat(_("Failed to download %s from %s")) % m_DataBaseName % thePrefs::GetGeoIPUpdateUrl());
154		// if it failed and there is no database, turn it off
155		if (!wxFileExists(m_DataBasePath)) {
156			thePrefs::SetGeoIPEnabled(false);
157		}
158	}
159}
160
161void CIP2Country::LoadFlags()
162{
163	// Load data from xpm files
164	for (int i = 0; i < flags::FLAGS_XPM_SIZE; ++i) {
165		CountryData countrydata;
166		countrydata.Name = char2unicode(flags::flagXPMCodeVector[i].code);
167		countrydata.Flag = wxImage(flags::flagXPMCodeVector[i].xpm);
168
169		if (countrydata.Flag.IsOk()) {
170			m_CountryDataMap[countrydata.Name] = countrydata;
171		} else {
172			AddLogLineC(CFormat(_("Failed to load country data for '%s'.")) % countrydata.Name);
173			continue;
174		}
175	}
176
177	AddDebugLogLineN(logGeneral, CFormat(wxT("Loaded %d flag bitmaps.")) % m_CountryDataMap.size());  // there's never just one - no plural needed
178}
179
180
181CIP2Country::~CIP2Country()
182{
183	Disable();
184}
185
186
187const CountryData& CIP2Country::GetCountryData(const wxString &ip)
188{
189	// Should prevent the crash if the GeoIP database does not exists
190	if (m_geoip == NULL) {
191		CountryDataMap::iterator it = m_CountryDataMap.find(wxString(wxT("unknown")));
192		it->second.Name = wxT("?");
193		return it->second;
194	}
195
196	const wxString CCode = wxString(char2unicode(GeoIP_country_code_by_addr(m_geoip, unicode2char(ip)))).MakeLower();
197
198	CountryDataMap::iterator it = m_CountryDataMap.find(CCode);
199	if (it == m_CountryDataMap.end()) {
200		// Show the code and ?? flag
201		it = m_CountryDataMap.find(wxString(wxT("unknown")));
202		wxASSERT(it != m_CountryDataMap.end());
203		if (CCode.IsEmpty()) {
204			it->second.Name = wxT("?");
205		} else{
206			it->second.Name = CCode;
207		}
208	}
209
210	return it->second;
211}
212
213#else
214
215#include "IP2Country.h"
216
217CIP2Country::CIP2Country(const wxString&)
218{
219	m_geoip = NULL;
220}
221
222CIP2Country::~CIP2Country() {}
223void CIP2Country::Enable() {}
224void CIP2Country::DownloadFinished(uint32) {}
225
226const CountryData& CIP2Country::GetCountryData(const wxString &)
227{
228	static CountryData dummy;
229	return dummy;
230}
231
232#endif // ENABLE_IP2COUNTRY
233