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