Fixes for cython 0.11-2.
[python-purple] / nullclient-ecore.py
1 #
2 #  Copyright (c) 2008 INdT - Instituto Nokia de Tecnologia
3 #
4 #  This file is part of python-purple.
5 #
6 #  python-purple 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 #  python-purple 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 import etk
21 import ecore
22 import sys, dl
23
24 sys.setdlopenflags(dl.RTLD_NOW | dl.RTLD_GLOBAL)
25
26 import purple
27
28 # The information below is needed by libpurple
29 __NAME__ = "nullclient-ecore"
30 __VERSION__ = "0.1"
31 __WEBSITE__ = "N/A"
32 __DEV_WEBSITE__ = "N/A"
33
34 class MainWindow(object):
35     def __init__(self):
36         # Connect button callback
37         self.__connect_button_cb = None
38
39         # Send button callback
40         self.__send_button_cb = None
41
42         # New account callback
43         self.__new_account_cb = None
44
45         # Exit callback
46         self.__exit_cb = None
47
48     def __login_window_cb(self, pointer):
49         # Password entry
50         self.login_password = etk.Entry()
51
52         # Confirm login button
53         confirm_login_bt = etk.Button(label='Ok')
54         confirm_login_bt.on_clicked(self.__connect_button_clicked)
55
56         # Login VBox
57         vbox = etk.VBox()
58         vbox.append(self.login_password, etk.VBox.START, etk.VBox.FILL, 0)
59         vbox.append(confirm_login_bt, etk.VBox.END, etk.VBox.NONE, 0)
60
61         # Login window
62         self.login_window = etk.Window(title='Password', \
63                 size_request=(190, 80), child=vbox)
64         self.login_window.show_all()
65
66     def __connect_button_clicked(self, pointer):
67         # Call connection button callback
68         if self.__connect_button_cb:
69             self.__connect_button_cb(self.login_password.text)
70         self.login_window.destroy()
71
72     def __send_button_clicked(self, pointer):
73         # Get selected buddy name from buddy list
74         bname = self.blist.selected_rows[0][0]
75
76         # Get message from command entry
77         msg = self.cmd_entry.text
78
79         if bname and msg != '':
80             # Call send button callback
81             if self.__send_button_cb:
82                 self.__send_button_cb(bname, msg)
83
84         # Clear text from command entry
85         self.cmd_entry.text = ''
86
87     def __new_account_button_clicked(self, pointer):
88         # Username entry
89         self.login_username = etk.Entry()
90
91         # Confirm username button
92         confirm_username_bt = etk.Button(label='Ok')
93         confirm_username_bt.on_clicked(self.add_account)
94
95         # Username VBox
96         vbox = etk.VBox()
97         vbox.append(self.login_username, etk.VBox.START, etk.VBox.FILL, 0)
98         vbox.append(confirm_username_bt, etk.VBox.END, etk.VBox.NONE, 0)
99
100         # Username window
101         self.username_window = etk.Window(title='Username', \
102                 size_request=(190, 80), child=vbox)
103         self.username_window.show_all()
104
105     def __create_accounts_list(self):
106         # Accounts list
107         self.accslistmodel = etk.ListModel()
108         self.accslist = etk.List(model=self.accslistmodel, \
109                 columns=[(10, etk.TextRenderer(slot=0), False)], \
110                 selectable=True, animated_changes=True)
111
112         #Appending accounts list to VBox
113         vbox = etk.VBox()
114         vbox.append(self.accslist, etk.VBox.START, etk.VBox.EXPAND_FILL, 0)
115         return vbox
116
117     def __create_buddies_list(self):
118         # Buddies list
119         self.blistmodel = etk.ListModel()
120         self.blist = etk.List(model=self.blistmodel, \
121                 columns=[(10, etk.TextRenderer(slot=0), False)], \
122                 selectable=True, animated_changes=True)
123
124         # Appending buddies list to VBox
125         vbox = etk.VBox()
126         vbox.append(self.blist, etk.VBox.START, etk.VBox.EXPAND_FILL, 0)
127         return vbox
128
129     def __create_buttons_bar(self):
130         # Send button
131         send_button = etk.Button(label='Send')
132         send_button.on_clicked(self.__send_button_clicked)
133
134         # Connect button
135         conn_button = etk.Button(label='Connect')
136         conn_button.on_clicked(self.__login_window_cb)
137
138         # New account button
139         new_acc_button = etk.Button(label='New Account')
140         new_acc_button.on_clicked(self.__new_account_button_clicked)
141
142         # Appending all buttons to HBox
143         hbox = etk.HBox(homogeneous=False)
144         hbox.append(send_button, etk.HBox.START, etk.HBox.NONE, 0)
145         hbox.append(conn_button, etk.HBox.START, etk.HBox.NONE, 0)
146         hbox.append(new_acc_button, etk.HBox.START, etk.HBox.NONE, 0)
147         return hbox
148
149     def __create_command_entry_box(self):
150         # Command entry box
151         self.cmd_entry = etk.Entry()
152         self.cmd_label = etk.Label(text='Type your message: ')
153
154         # appending command entry and label to HBox
155         hbox = etk.HBox(homogeneous=False)
156         hbox.append(self.cmd_label, etk.HBox.START, \
157                 etk.HBox.START, 0)
158         hbox.append(self.cmd_entry, etk.HBox.START, \
159                 etk.HBox.EXPAND_FILL, 0)
160         return hbox
161
162     def __create_text_area(self):
163         # Text area (shows buddy messages)
164         self.txt_area = etk.Label()
165         self.txt_area.text = '<br>Nullclient-Ecore<br> '
166
167         # Appending text area to VBox
168         vbox = etk.VBox()
169         vbox.append(self.txt_area, etk.VBox.START, etk.VBox.EXPAND_FILL, 0)
170         return vbox
171
172     def __create_main_panel(self):
173         # Text box
174         txt_vbox = self.__create_text_area()
175
176         # Buddies list
177         bdd_vbox = self.__create_buddies_list()
178
179         # Accounts list
180         acc_vbox = self.__create_accounts_list()
181
182         # Appending text area, buddies list and accounts list to HBox
183         hbox = etk.HBox()
184         hbox.append(txt_vbox, etk.HBox.START, etk.HBox.EXPAND_FILL, 0)
185         hbox.append(bdd_vbox, etk.HBox.END, etk.HBox.EXPAND_FILL, 0)
186         hbox.append(acc_vbox, etk.HBox.END, etk.HBox.EXPAND_FILL, 0)
187         return hbox
188
189     def __create_main_box(self):
190         # Main panel
191         panel_hbox = self.__create_main_panel()
192
193         # Command entry
194         cmd_hbox = self.__create_command_entry_box()
195
196         # Buttons Bar
197         btn_hbox = self.__create_buttons_bar()
198
199         # Connection status
200         self.status = etk.Label(text='Connection status')
201
202         # Main VBox
203         vbox = etk.VBox(homogeneous=False)
204         vbox.append(panel_hbox, etk.VBox.START, etk.VBox.EXPAND_FILL, 0)
205         vbox.append(cmd_hbox, etk.VBox.END, etk.VBox.FILL, 0)
206         vbox.append(btn_hbox, etk.VBox.END, etk.VBox.NONE, 5)
207         vbox.append(self.status, etk.VBox.END, etk.VBox.FILL, 0)
208         return vbox
209
210     def get_selected_account(self):
211         # Catch selected account from accounts list
212         try:
213             account = self.accslist.selected_rows[0][0]
214             if account:
215                 return account
216             else:
217                 return None
218         except:
219             return None
220
221     def add_buddy(self, name):
222         # Adds a new buddy into buddy list
223         if [name] not in self.blistmodel.elements:
224             self.blistmodel.append([name])
225
226     def remove_buddy(self, name):
227         # Removes a buddy from buddy list
228         self.blistmodel.remove([name])
229
230     def add_account(self, pointer):
231         # Adds a new account into accounts list
232         if [self.login_username.text] not in self.accslistmodel.elements:
233             self.accslistmodel.append([self.login_username.text])
234         self.username_window.destroy()
235         self.window.show_all()
236
237     def add_connection_button_cb(self, cb):
238         if callable(cb):
239             self.__connect_button_cb = cb
240
241     def add_new_account_cb(self, cb):
242         if callable(cb):
243             self.__new_account_cb = cb
244
245     def add_send_button_cb(self, cb):
246         if callable(cb):
247             self.__send_button_cb = cb
248
249     def add_exit_cb(self, cb):
250         if callable(cb):
251             self.__exit_cb = cb
252
253     def init_window(self):
254         # Main box
255         main_box = self.__create_main_box()
256
257         # Main Window
258         self.window = etk.Window(title='Nullclient-Ecore', \
259                 size_request=(600, 600), child=main_box)
260         self.window.on_destroyed(self.__exit_cb)
261         self.window.show_all()
262
263     def show(self):
264         if self.window:
265             self.window.show_all()
266
267 class NullClient(object):
268     def __init__(self):
269         # Sets initial parameters
270         self.core = purple.Purple(__NAME__, __VERSION__, __WEBSITE__, \
271                 __DEV_WEBSITE__, debug_enabled=True, default_path='/tmp')
272         ecore.Timer(0.01, self.core.iterate_main_loop)
273         self.account = None
274         self.buddies = {}
275         self.conversations = {}
276         self.protocol = purple.Protocol('prpl-jabber')
277         self.window = MainWindow()
278
279         # Adds libpurple core callbacks
280
281         # Updates buddy list
282         self.core.add_callback('blist', 'update', \
283                 self.__update_blist_cb)
284
285         # Updates connection progress
286         self.core.add_callback('connection', 'connect-progress', \
287                 self.__connection_progress_cb)
288
289         # Activates when an account is connected
290         self.core.add_callback('connection', 'connected', \
291                 self.__connected_cb)
292
293         # Activates when an account is disconnected
294         self.core.add_callback('connection', 'disconnected', \
295                 self.__disconected_cb)
296
297         # Activates when a message is sent or received from conversation
298         self.core.add_callback('conversation', 'write-im', \
299                 self.__write_im_cb)
300
301         # Signal when account signed on
302         self.core.signal_connect('signed-on', self.__signed_on_cb)
303
304         # Signal when account signed off
305         self.core.signal_connect('signed-off', self.__signed_off_cb)
306
307         # Signal when buddy signed on
308         self.core.signal_connect('buddy-signed-on', self.__buddy_signed_on_cb)
309
310         # Signed when buddy signed off
311         self.core.signal_connect('buddy-signed-off', self.__buddy_signed_off_cb)
312
313         # Adds UI callbacks
314         self.window.add_connection_button_cb(self.connect)
315         self.window.add_send_button_cb(self.send_message)
316         self.window.add_exit_cb(self.exit)
317
318         # Initializes libpurple
319         self.core.purple_init()
320
321         # Initializes UI
322         self.window.init_window()
323
324     def __update_blist_cb(self, type, name=None, alias=None):
325         if self.account and name and type == 2:
326             if name not in self.buddies:
327                 self.buddies[name] = purple.Buddy(name, self.account)
328             if self.buddies[name].online:
329                 self.window.add_buddy(name)
330
331     def __connection_progress_cb(self, text, step, step_count):
332         if self.window:
333             self.window.status.text = text
334
335     def __connected_cb(self, *data):
336         if self.window:
337             self.window.status.text = 'Connected'
338
339     def __disconected_cb():
340         if self.window:
341             self.window.status.text = 'Disconnected'
342
343     def __write_im_cb(self, username, name, alias, message, flags):
344         if self.window:
345             if 'SEND' == flags:
346                 self.window.txt_area.text += username + ": " + message + "<br> "
347             elif alias:
348                 self.window.txt_area.text += alias + ": " + message + "<br> "
349             else:
350                 self.window.txt_area.text += name + ": " + message + "<br> "
351             self.window.show()
352
353     def __signed_on_cb(self, username, protocol_id):
354         if self.window:
355             self.window.txt_area += 'Signed on: %s (%s)' % (username, protocol_id)
356             self.window.show()
357
358     def __signed_off_cb(self, username, protocol_id):
359         if self.window:
360             self.window.txt_area += 'Signed off: %s (%s)' % (username, protocol_id)
361             self.window.show()
362
363     def __buddy_signed_on_cb(self, name, alias):
364         if self.window:
365             self.window.txt_area += 'Buddy signed on: %s (%s)' % (name, alias)
366             self.window.show()
367
368     def __buddy_signed_off_cb(self, name, alias):
369         if name in self.buddies:
370             del self.buddies[name]
371
372         if self.window:
373             self.window.txt_area += 'Buddy signed off: %s (%s)' % (name, alias)
374             self.window.remove_buddy(name)
375             self.window.show()
376
377     def connect(self, password):
378         username = self.window.get_selected_account()
379         if username and password:
380             self.account = purple.Account(username, self.protocol, self.core)
381             if not self.account.exists:
382                 self.account.new()
383                 info = {}
384                 info['connect_server'] = 'talk.google.com'
385                 info['port'] = '443'
386                 info['old_ssl'] = True
387                 self.account.set_protocol_options(info)
388
389             self.account.set_password(password)
390             self.account.set_enabled(True)
391
392     def send_message(self, name, message):
393         print name, message
394         if name not in self.conversations:
395             self.conversations[name] = purple.Conversation('IM', self.account, name)
396             self.conversations[name].new()
397
398         self.conversations[name].im_send(message)
399
400     def exit(self, pointer):
401         ecore.main_loop_quit()
402
403 if __name__ == '__main__':
404     client = NullClient()
405
406     # Initializes ecore mainloop
407     ecore.main_loop_begin()