1 // This file is part of GtkEveMon.
2 //
3 // GtkEveMon is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // You should have received a copy of the GNU General Public License
9 // along with GtkEveMon. If not, see <http://www.gnu.org/licenses/>.
10 
11 #include <sstream>
12 #include <fstream>
13 #include <iostream>
14 
15 #include <gtkmm.h>
16 
17 #include "util/os.h"
18 #include "net/http.h"
19 #include "bits/config.h"
20 #include "imagestore.h"
21 #include "gtkportrait.h"
22 
GtkPortrait(void)23 GtkPortrait::GtkPortrait (void)
24 {
25   this->add(this->image);
26 }
27 
28 /* ---------------------------------------------------------------- */
29 
GtkPortrait(std::string const & charid)30 GtkPortrait::GtkPortrait (std::string const& charid)
31 {
32   this->set(charid);
33 }
34 
35 /* ---------------------------------------------------------------- */
36 
~GtkPortrait(void)37 GtkPortrait::~GtkPortrait (void)
38 {
39   this->http_request.disconnect();
40 }
41 
42 /* ---------------------------------------------------------------- */
43 
44 void
set(std::string const & charid)45 GtkPortrait::set (std::string const& charid)
46 {
47   this->char_id = charid;
48 
49   bool success = false;
50 
51   /* Try to get the portrait from our own cache. */
52   success = this->fetch_from_gtkevemon_cache();
53 
54   /* Use default image and request online. */
55   if (!success)
56   {
57     Glib::RefPtr<Gdk::Pixbuf> pixbuf = ImageStore::eveportrait;
58     Glib::RefPtr<Gdk::Pixbuf> scaled = pixbuf->scale_simple
59         (PORTRAIT_SIZE, PORTRAIT_SIZE, Gdk::INTERP_BILINEAR);
60     this->image.set(scaled);
61     this->request_from_eve_online();
62   }
63 }
64 
65 /* ---------------------------------------------------------------- */
66 
67 void
set_enable_clicks(void)68 GtkPortrait::set_enable_clicks (void)
69 {
70   this->signal_button_press_event().connect(sigc::mem_fun
71       (*this, &GtkPortrait::on_button_press_myevent));
72 }
73 
74 /* ---------------------------------------------------------------- */
75 
76 void
update(void)77 GtkPortrait::update (void)
78 {
79   this->set(this->char_id);
80 }
81 
82 /* ---------------------------------------------------------------- */
83 
84 bool
fetch_from_gtkevemon_cache(void)85 GtkPortrait::fetch_from_gtkevemon_cache (void)
86 {
87   bool success = false;
88 
89   try
90   {
91     std::string portraitdir = Config::get_conf_dir() + "/portraits";
92     std::stringstream filename;
93     filename << portraitdir << "/" << this->char_id
94         << "_" << PORTRAIT_SIZE << ".png";
95 
96     Glib::RefPtr<Gdk::Pixbuf> portrait = GtkPortrait::create_from_file
97         (filename.str());
98     this->image.set(portrait);
99     success = true;
100   }
101   catch (...)
102   {
103   }
104 
105   //if (success)
106   //  std::cout << "Using protrait from GtkEveMon cache!" << std::endl;
107 
108   return success;
109 }
110 
111 /* ---------------------------------------------------------------- */
112 
113 void
request_from_eve_online(void)114 GtkPortrait::request_from_eve_online (void)
115 {
116   std::cout << "Requesting portrait: " << this->char_id
117       << " ..." << std::endl;
118 
119   AsyncHttp* http = AsyncHttp::create();;
120   //http->set_host("img.eve.is");
121   //http->set_path("/serv.asp?s=256&c=" + this->char_id);
122   http->set_host("image.eveonline.com");
123   http->set_path("/Character/" + this->char_id + "_256.jpg");
124   Config::setup_http(http, true);
125 
126   this->http_request.disconnect();
127   this->http_request = http->signal_done().connect(sigc::mem_fun
128       (*this, &GtkPortrait::set_from_eve_online));
129 
130   http->async_request();
131 }
132 
133 /* ---------------------------------------------------------------- */
134 
135 void
set_from_eve_online(AsyncHttpData result)136 GtkPortrait::set_from_eve_online (AsyncHttpData result)
137 {
138   if (result.data.get() == 0)
139   {
140     std::cout << "Error fetching portrait from EVE Online!" << std::endl;
141     return;
142   }
143 
144   if (result.data->http_code != 200)
145   {
146     std::cout << "Error fetching portrait: " << result.exception << std::endl;
147     return;
148   }
149 
150   /* Generate filenames to store the fetched JPG and the destination PNG. */
151   std::string confdir = Config::get_conf_dir();
152   std::stringstream jpg_name;
153   jpg_name << confdir << "/" << this->char_id << "_256.jpg";
154 
155   try
156   {
157     std::ofstream out(jpg_name.str().c_str(), std::ios::binary);
158     out.write(&result.data->data[0], result.data->data.size() - 1);
159     out.close();
160 
161     Glib::RefPtr<Gdk::Pixbuf> image
162         = GtkPortrait::create_from_file(jpg_name.str())
163         ->scale_simple(PORTRAIT_SIZE, PORTRAIT_SIZE, Gdk::INTERP_BILINEAR);
164 
165     this->cache_portrait(image);
166     OS::unlink(jpg_name.str().c_str());
167     this->fetch_from_gtkevemon_cache();
168   }
169   catch (...)
170   {
171     OS::unlink(jpg_name.str().c_str());
172     std::cout << "Error saving portrait from EVE Online" << std::endl;
173     return;
174   }
175 }
176 
177 /* ---------------------------------------------------------------- */
178 
179 void
cache_portrait(Glib::RefPtr<Gdk::Pixbuf> portrait)180 GtkPortrait::cache_portrait (Glib::RefPtr<Gdk::Pixbuf> portrait)
181 {
182   std::string portraitdir = Config::get_conf_dir() + "/portraits";
183 
184   /* Create portrait directory if it does not exist. */
185   bool dir_exists = OS::dir_exists(portraitdir.c_str());
186   if (!dir_exists)
187   {
188     /* Ignore errors. We'll get them on creation. */
189     OS::mkdir(portraitdir.c_str());
190   }
191 
192   try
193   {
194     std::string filename = this->get_portrait_file();
195     GtkPortrait::save_to_file(portrait, filename);
196   }
197   catch (...)
198   {
199     std::cout << "Error caching portrait for " << this->char_id << std::endl;
200     return;
201   }
202 
203   std::cout << "Cached portrait: " << this->char_id << std::endl;
204 }
205 
206 /* ---------------------------------------------------------------- */
207 
208 bool
on_button_press_myevent(GdkEventButton *)209 GtkPortrait::on_button_press_myevent (GdkEventButton* /*event*/)
210 {
211   this->request_from_eve_online();
212 
213   Gtk::Window* toplevel = (Gtk::Window*)this->get_toplevel();
214   Gtk::MessageDialog md("Portrait has been re-requested!",
215       false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK);
216   md.set_secondary_text("A new portrait has been requested from the "
217       "EVE image server. If you can only see a \"!\" as portrait, "
218       "the image server most likely does not have the portrait. This "
219       "happens to new players or after a portrait server reset.\n\n"
220       "If you can see a \"!\" and the text \"GtkEveMon fallback\", the "
221       "portrait couldn't be requested and a local fallback is used.\n\n"
222       "Image URL:\n"
223       "https://image.eveonline.com/Character/" + this->char_id + "_256.jpg");
224   md.set_title("Portrait re-request - GtkEveMon");
225   md.set_transient_for(*toplevel);
226   md.run();
227 
228   return true;
229 }
230 
231 /* ---------------------------------------------------------------- */
232 
233 std::string
get_portrait_dir(void)234 GtkPortrait::get_portrait_dir (void)
235 {
236   return Config::get_conf_dir() + "/portraits";
237 }
238 
239 /* ---------------------------------------------------------------- */
240 
241 std::string
get_portrait_file(void)242 GtkPortrait::get_portrait_file (void)
243 {
244   std::stringstream filename;
245   filename << this->get_portrait_dir();
246   filename << "/" << this->char_id << "_" << PORTRAIT_SIZE << ".png";
247   return filename.str();
248 }
249 
250 /* ---------------------------------------------------------------- */
251 
252 Glib::RefPtr<Gdk::Pixbuf>
create_from_file(std::string const & fn)253 GtkPortrait::create_from_file (std::string const& fn)
254 {
255   #ifdef GLIBMM_EXCEPTIONS_ENABLED
256   return Gdk::Pixbuf::create_from_file(fn);
257   #else
258   std::auto_ptr<Glib::Error> error;
259   Glib::RefPtr<Gdk::Pixbuf> ret = Gdk::Pixbuf::create_from_file(fn, error);
260   if (error.get())
261     throw error;
262   return ret;
263   #endif
264 }
265 
266 /* ---------------------------------------------------------------- */
267 
268 void
save_to_file(Glib::RefPtr<Gdk::Pixbuf> pixbuf,std::string const & fn)269 GtkPortrait::save_to_file (Glib::RefPtr<Gdk::Pixbuf> pixbuf,
270     std::string const& fn)
271 {
272   #ifdef GLIBMM_EXCEPTIONS_ENABLED
273   pixbuf->save(fn, "png");
274   #else
275   std::auto_ptr<Glib::Error> error;
276   pixbuf->save(fn, "png", error);
277   if (error.get())
278     throw error;
279   #endif
280 }
281