1 /*
2  *  This file is part of the "GKMap".
3  *  GKMap project borrowed from GMap.NET (by radioman).
4  *
5  *  Copyright (C) 2009-2018 by radioman (email@radioman.lt).
6  *  This program is licensed under the FLAT EARTH License.
7  */
8 
9 using System;
10 using System.Collections.Generic;
11 using System.Diagnostics;
12 using System.IO;
13 using System.Net;
14 using System.Security.Cryptography;
15 using System.Text;
16 
17 namespace GKMap.MapProviders
18 {
19     /// <summary>
20     /// base class for each map provider
21     /// </summary>
22     public abstract class GMapProvider
23     {
24         /// <summary>
25         /// Time to live of cache, in hours. Default: 240 (10 days).
26         /// </summary>
27         public static int TTLCache = 240;
28 
29         private string fAuthorization = string.Empty;
30         private bool fIsInitialized;
31 
32         private static string fLanguageStr = "en";
33         private static LanguageType fLanguage = LanguageType.English;
34 
35         /// <summary>
36         /// was provider initialized
37         /// </summary>
38         public bool IsInitialized
39         {
40             get {
41                 return fIsInitialized;
42             }
43             internal set {
44                 fIsInitialized = value;
45             }
46         }
47 
48         /// <summary>
49         /// unique provider id
50         /// </summary>
51         public virtual Guid Id
52         {
53             get {
54                 throw new NotImplementedException();
55             }
56         }
57 
58         /// <summary>
59         /// provider name
60         /// </summary>
61         public virtual string Name
62         {
63             get {
64                 throw new NotImplementedException();
65             }
66         }
67 
68         /// <summary>
69         /// provider projection
70         /// </summary>
71         public virtual PureProjection Projection
72         {
73             get {
74                 throw new NotImplementedException();
75             }
76         }
77 
78         /// <summary>
79         /// provider overlays
80         /// </summary>
81         public virtual GMapProvider[] Overlays
82         {
83             get {
84                 throw new NotImplementedException();
85             }
86         }
87 
88         /// <summary>
89         /// gets tile image using implemented provider
90         /// </summary>
91         /// <param name="pos"></param>
92         /// <param name="zoom"></param>
93         /// <returns></returns>
GetTileImage(GPoint pos, int zoom)94         public virtual PureImage GetTileImage(GPoint pos, int zoom)
95         {
96             throw new NotImplementedException();
97         }
98 
99         private static readonly List<GMapProvider> MapProviders = new List<GMapProvider>();
100 
GMapProvider()101         protected GMapProvider()
102         {
103             using (var HashProvider = new SHA1CryptoServiceProvider()) {
104                 DbId = Math.Abs(BitConverter.ToInt32(HashProvider.ComputeHash(Id.ToByteArray()), 0));
105             }
106 
107             if (MapProviders.Exists(p => p.Id == Id || p.DbId == DbId)) {
108                 throw new Exception("such provider id already exists, try regenerate your provider guid...");
109             }
110             MapProviders.Add(this);
111         }
112 
113         /// <summary>
114         /// id for database, a hash of provider guid
115         /// </summary>
116         public readonly int DbId;
117 
118         /// <summary>
119         /// area of map
120         /// </summary>
121         public RectLatLng? Area;
122 
123         /// <summary>
124         /// minimum level of zoom
125         /// </summary>
126         public int MinZoom;
127 
128         /// <summary>
129         /// maximum level of zoom
130         /// </summary>
131         public int? MaxZoom = 17;
132 
133         /// <summary>
134         /// proxy for net access
135         /// </summary>
136         public static IWebProxy WebProxy;
137 
138         /// <summary>
139         /// Connect trough a SOCKS 4/5 proxy server
140         /// </summary>
141         public static bool IsSocksProxy = false;
142 
143         /// <summary>
144         /// NetworkCredential for tile http access
145         /// </summary>
146         public static ICredentials Credential;
147 
148         /// <summary>
149         /// Gets or sets the value of the User-agent HTTP header.
150         /// It's pseudo-randomized to avoid blockages...
151         /// </summary>
152         public static string UserAgent = string.Format("Mozilla/5.0 (Windows NT {1}.0; {2}rv:{0}.0) Gecko/20100101 Firefox/{0}.0",
153             Stuff.Random.Next(DateTime.Today.Year - 1969 - 5, DateTime.Today.Year - 1969),
154             Stuff.Random.Next(0, 10) % 2 == 0 ? 10 : 6,
155             Stuff.Random.Next(0, 10) % 2 == 1 ? string.Empty : "WOW64; ");
156 
157         /// <summary>
158         /// timeout for provider connections
159         /// </summary>
160         public static int TimeoutMs = 10 * 1000;
161 
162         /// <summary>
163         /// Gets or sets the value of the Referer HTTP header.
164         /// </summary>
165         public string RefererUrl = string.Empty;
166 
167         public string Copyright = string.Empty;
168 
169         /// <summary>
170         /// true if tile origin at BottomLeft, WMS-C
171         /// </summary>
172         public bool InvertedAxisY = false;
173 
174         public static string LanguageStr
175         {
176             get {
177                 return fLanguageStr;
178             }
179         }
180 
181         /// <summary>
182         /// map language
183         /// </summary>
184         public static LanguageType Language
185         {
186             get {
187                 return fLanguage;
188             }
189             set {
190                 fLanguage = value;
191                 fLanguageStr = Stuff.EnumToString(fLanguage);
192             }
193         }
194 
195         private static readonly string RequestAccept = "*/*";
196         private static readonly string ResponseContentType = "image";
197 
198 
GMapProvider()199         static GMapProvider()
200         {
201             WebProxy = EmptyWebProxy.Instance;
202         }
203 
204         /// <summary>
205         /// called before first use
206         /// </summary>
OnInitialized()207         public virtual void OnInitialized()
208         {
209             // nice place to detect current provider version
210         }
211 
CheckTileImageHttpResponse(WebResponse response)212         protected virtual bool CheckTileImageHttpResponse(WebResponse response)
213         {
214             //Debug.WriteLine(response.StatusCode + "/" + response.StatusDescription + "/" + response.ContentType + " -> " + response.ResponseUri);
215             return response.ContentType.Contains(ResponseContentType);
216         }
217 
218         /// <summary>
219         /// http://blog.kowalczyk.info/article/at3/Forcing-basic-http-authentication-for-HttpWebReq.html
220         /// </summary>
221         /// <param name="userName"></param>
222         /// <param name="userPassword"></param>
ForceBasicHttpAuthentication(string userName, string userPassword)223         public void ForceBasicHttpAuthentication(string userName, string userPassword)
224         {
225             fAuthorization = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(userName + ":" + userPassword));
226         }
227 
GetRequest(string url)228         private WebRequest GetRequest(string url)
229         {
230             WebRequest request = IsSocksProxy ? SocksHttpWebRequest.Create(url) : WebRequest.Create(url);
231 
232             if (WebProxy != null) {
233                 request.Proxy = WebProxy;
234             }
235 
236             if (Credential != null) {
237                 request.PreAuthenticate = true;
238                 request.Credentials = Credential;
239             }
240 
241             if (!string.IsNullOrEmpty(fAuthorization)) {
242                 request.Headers.Set("Authorization", fAuthorization);
243             }
244 
245             if (request is HttpWebRequest) {
246                 var r = request as HttpWebRequest;
247                 r.UserAgent = UserAgent;
248                 r.ReadWriteTimeout = TimeoutMs * 6;
249                 r.Accept = RequestAccept;
250                 r.Referer = RefererUrl;
251                 r.Timeout = TimeoutMs;
252             } else if (request is SocksHttpWebRequest) {
253                 var r = request as SocksHttpWebRequest;
254 
255                 if (!string.IsNullOrEmpty(UserAgent)) {
256                     r.Headers.Add("User-Agent", UserAgent);
257                 }
258 
259                 if (!string.IsNullOrEmpty(RequestAccept)) {
260                     r.Headers.Add("Accept", RequestAccept);
261                 }
262 
263                 if (!string.IsNullOrEmpty(RefererUrl)) {
264                     r.Headers.Add("Referer", RefererUrl);
265                 }
266             }
267 
268             return request;
269         }
270 
GetTileImageUsingHttp(string url)271         protected PureImage GetTileImageUsingHttp(string url)
272         {
273             PureImage ret = null;
274 
275             WebRequest request = GetRequest(url);
276             using (var response = request.GetResponse()) {
277                 if (CheckTileImageHttpResponse(response)) {
278                     using (Stream responseStream = response.GetResponseStream()) {
279                         MemoryStream data = Stuff.CopyStream(responseStream, false);
280 
281                         Debug.WriteLine("Response[" + data.Length + " bytes]: " + url);
282 
283                         if (data.Length > 0) {
284                             ret = GMaps.TileImageProxy.FromStream(data);
285 
286                             if (ret != null) {
287                                 ret.Data = data;
288                                 ret.Data.Position = 0;
289                             } else {
290                                 data.Dispose();
291                             }
292                         }
293                     }
294                 } else {
295                     Debug.WriteLine("CheckTileImageHttpResponse[false]: " + url);
296                 }
297                 response.Close();
298             }
299             return ret;
300         }
301 
GetContentUsingHttp(string url)302         protected string GetContentUsingHttp(string url)
303         {
304             string ret;
305 
306             WebRequest request = GetRequest(url);
307             using (var response = request.GetResponse()) {
308                 using (Stream responseStream = response.GetResponseStream()) {
309                     using (StreamReader read = new StreamReader(responseStream, Encoding.UTF8)) {
310                         ret = read.ReadToEnd();
311                     }
312                 }
313                 response.Close();
314             }
315 
316             return ret;
317         }
318 
GetServerNum(GPoint pos, int max)319         protected static int GetServerNum(GPoint pos, int max)
320         {
321             return (int)(pos.X + 2 * pos.Y) % max;
322         }
323 
GetHashCode()324         public override int GetHashCode()
325         {
326             return DbId;
327         }
328 
Equals(object obj)329         public override bool Equals(object obj)
330         {
331             if (obj is GMapProvider) {
332                 return Id.Equals(((GMapProvider) obj).Id);
333             }
334             return false;
335         }
336 
ToString()337         public override string ToString()
338         {
339             return Name;
340         }
341     }
342 }
343