Hopefully fix bug #5672
[mevemon] / package / src / mevemon.py
1 #!/usr/bin/env python
2 #
3 # mEveMon - A character monitor for EVE Online
4 # Copyright (c) 2010  Ryan and Danny Campbell, and the mEveMon Team
5 #
6 # mEveMon is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # mEveMon is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 #
19
20
21 import hildon
22 import gtk
23 from eveapi import eveapi
24 import fetchimg
25 import apicache
26 import os.path
27
28 #conic is used for connection handling
29 import conic
30 #import socket for handling socket exceptions
31 import socket
32
33 # we will store our preferences in gconf
34 import gnome.gconf
35
36 #ugly hack to check maemo version. any better way?
37 if hasattr(hildon, "StackableWindow"):
38     from ui.fremantle import gui
39 else:
40     from ui.diablo import gui
41
42 class mEveMon():
43     """
44     The controller class for mEvemon. The intent is to help
45     abstract the EVE API and settings code from the UI code.
46
47     """
48
49     GCONF_DIR = "/apps/maemo/mevemon"
50
51     def __init__(self):
52         self.program = hildon.Program()
53         self.program.__init__()
54         self.gconf = gnome.gconf.client_get_default()
55         #NOTE: remove this after a few releases
56         self.update_settings()
57         self.connect()
58         self.cached_api = eveapi.EVEAPIConnection( cacheHandler = \
59                 apicache.cache_handler(debug=False))
60         self.gui = gui.mEveMonUI(self)
61
62     def run(self):
63         gtk.main()
64     
65     def quit(self, *args):
66         gtk.main_quit()
67
68     def update_settings(self):
69         """
70         Update from the old pre 0.3 settings to the new settings layout.
71         We should remove this eventually, once no one is using pre-0.3 mEveMon
72         """
73         uid = self.gconf.get_string("%s/eve_uid" % self.GCONF_DIR)
74         
75         if uid:
76             key = self.gconf.get_string("%s/eve_api_key" % self.GCONF_DIR)
77             self.add_account(uid, key)
78             self.gconf.unset("%s/eve_uid" % self.GCONF_DIR)
79             self.gconf.unset("%s/eve_api_key" % self.GCONF_DIR)
80
81
82     def get_accounts(self):
83         """
84         Returns a dictionary containing uid:api_key pairs gathered from gconf
85         """
86         accounts = {}
87         entries = self.gconf.all_entries("%s/accounts" % self.GCONF_DIR)
88
89         for entry in entries:
90             key = os.path.basename(entry.get_key())
91             value = entry.get_value().to_string()
92             accounts[key] = value
93
94         return accounts
95         
96     def get_api_key(self, uid):
97         """
98         Returns the api key associated with the given uid.
99         """
100         return self.gconf.get_string("%s/accounts/%s" % (self.GCONF_DIR, uid)) or ''
101
102     def remove_account(self, uid):
103         """
104         Removes the provided uid key from gconf
105         """
106         self.gconf.unset("%s/accounts/%s" % (self.GCONF_DIR, uid))
107
108     def add_account(self, uid, api_key):
109         """
110         Adds the provided uid:api_key pair to gconf.
111         """
112         self.gconf.set_string("%s/accounts/%s" % (self.GCONF_DIR, uid), api_key)
113
114     def get_auth(self, uid):
115         """
116         Returns an authentication object to be used for eveapi calls
117         that require authentication.
118         """
119         api_key = self.get_api_key(uid)
120
121         try:
122             auth = self.cached_api.auth(userID=uid, apiKey=api_key)
123         except: 
124             return None
125
126         return auth
127
128     def get_char_sheet(self, uid, char_id):
129         """
130         Returns an object containing information about the character specified
131         by the provided character ID.
132         """
133         try:
134             sheet = self.get_auth(uid).character(char_id).CharacterSheet()
135         except:
136             # TODO: we should really have a logger that logs this error somewhere
137             return None
138
139         return sheet
140
141     def charid2uid(self, char_id):
142         """
143         Takes a character ID and returns the user ID of the account containing
144         the character.
145
146         Returns None if the character isn't found in any of the registered accounts.
147
148         """
149         acct_dict = self.get_accounts()
150         
151         for uid, api_key in acct_dict.items():
152             auth = self.cached_api.auth(userID=uid, apiKey=api_key)
153             api_char_list = auth.account.Characters()
154             
155             for character in api_char_list.characters:
156                 if character.characterID == char_id:
157                     return uid
158
159         
160         return None
161     
162     def char_id2name(self, char_id):
163         """
164         Takes a character ID and returns the character name associated with
165         that ID.
166         The EVE API accepts a comma-separated list of IDs, but for now we
167         will just handle a single ID.
168         """
169         try:
170             chars = self.cached_api.eve.CharacterName(ids=char_id).characters
171             name = chars[0].characterName
172         except:
173             return None
174
175         return name
176
177     def char_name2id(self, name):
178         """
179         Takes the name of an EVE character and returns the characterID.
180         
181         The EVE api accepts a comma separated list of names, but for now
182         we will just handle single names/
183         """
184         try:
185             chars = self.cached_api.eve.CharacterID(names=name).characters
186             char_id = chars[0].characterID
187             char_name = chars[0].name
188         except:
189             return None
190
191         return char_id
192
193     def get_chars_from_acct(self, uid):
194         """
195         Returns a list of characters associated with the provided user ID.
196         """
197         auth = self.get_auth(uid)
198         if not auth:
199             return None
200         else:
201             try:
202                 api_char_list = auth.account.Characters()
203                 char_list = [char.name for char in api_char_list.characters]
204             except:
205                 return None
206
207         return char_list
208
209     def get_characters(self):
210         """
211         Returns a list of (character_name, image_path, uid) tuples from all the
212         accounts that are registered to mEveMon.
213         
214         If there is an authentication issue, then instead of adding a valid
215         pair to the list, it appends an 'error message' 
216
217         """
218         ui_char_list = []
219         err_img = "/usr/share/mevemon/imgs/error.jpg"
220
221         placeholder_chars = ("Please check your API settings.", err_img, "0")
222         
223         acct_dict = self.get_accounts()
224         if not acct_dict:
225             return [placeholder_chars]
226
227         for uid in acct_dict.keys():
228             char_names = self.get_chars_from_acct(uid)
229             
230             if not char_names:
231                 ui_char_list.append(placeholder_chars)
232             else:
233                 # append each char we get to the list we'll return to the
234                 # UI --danny
235                 for char_name in char_names:
236                     ui_char_list.append((char_name, self.get_portrait(char_name, 64) , uid) )
237         
238         return ui_char_list
239
240     def get_portrait(self, char_name, size):
241         """
242         Returns the file path of the retrieved portrait
243         """
244         char_id = self.char_name2id(char_name)
245         
246         return fetchimg.portrait_filename(char_id, size)
247
248     def get_skill_tree(self):
249         """
250         Returns an object from eveapi containing skill tree info
251         """
252         try:
253             tree = self.cached_api.eve.SkillTree()
254         except:
255             return None
256         
257         return tree
258
259     def get_skill_in_training(self, uid, char_id):
260         """
261         Returns an object from eveapi containing information about the
262         current skill in training
263
264         """
265         try:
266             skill = self.get_auth(uid).character(char_id).SkillInTraining()
267         except:
268             return None
269
270         return skill
271
272     def connection_cb(self, connection, event, mgc):
273         pass    
274
275
276     def connect(self):
277         connection = conic.Connection()
278         #why 0xAA55?
279         connection.connect("connection-event", self.connection_cb, 0xAA55)
280         assert(connection.request_connection(conic.CONNECT_FLAG_NONE))
281
282
283 if __name__ == "__main__":
284     app = mEveMon()
285     app.run()