Dump the hashmaps
[gregoa/zavai.git] / test / test-gsm-receive.vala
1 /*
2  * test-gsm-receive - Play with receiving GSM data
3  *
4  * Copyright (C) 2010  Enrico Zini <enrico@enricozini.org>
5  *
6  * This program 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 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 using GLib;
22
23 public DBus.Connection sbus;
24
25 //string VERSION = "0.1";
26
27 public class GSMReceive: Object //, zavai.Resource
28 {
29     public dynamic DBus.Object device;
30     public dynamic DBus.Object network;
31     public dynamic DBus.Object call;
32
33     public GSMReceive()
34     {
35         //zavai.gsm.gsm.request("GSMReceive");
36
37         device = sbus.get_object(
38                     "org.freesmartphone.ogsmd",
39                     "/org/freesmartphone/GSM/Device",
40                     "org.freesmartphone.GSM.Device");
41
42         network = sbus.get_object(
43             "org.freesmartphone.ogsmd", 
44             "/org/freesmartphone/GSM/Device",
45             "org.freesmartphone.GSM.Network");
46
47         call = sbus.get_object(
48                 "org.freesmartphone.ogsmd",
49                 "/org/freesmartphone/GSM/Device",
50                 "org.freesmartphone.GSM.Call");
51
52         stderr.printf("Antenna is %s\n", device.GetAntennaPower() ? "on" : "off");
53         stderr.printf("Signal strength: %d\n", network.GetSignalStrength());
54         stderr.printf("Calling identification: %s\n", network.GetCallingIdentification());
55         GLib.HashTable<string, GLib.Value?> status = network.GetStatus();
56         stderr.printf("Network status:\n");
57         dump_table(status);
58
59         network.Status += on_network_Status;
60         network.SignalStrength += on_network_SignalStrength;
61         call.CallStatus += on_call_Status;
62     }
63
64     public void shutdown()
65     {
66         //zavai.gsm.gsm.release("GSMReceive");
67     }
68
69     protected void dump_table(HashTable<string, Value?> vals)
70     {
71         vals.for_each((pk, pv) => {
72                 string k = (string)pk;
73                 Value? v = (Value?)pv;
74                 stderr.printf("K: %s V: %s\n", k, v == null ? "(null)" : v.strdup_contents());
75         });
76     }
77
78     public void on_network_SignalStrength(DBus.Object sender, int strength)
79     {
80         stderr.printf("SIGNAL STRENGTH %d\n", strength);
81     }
82
83     public void on_network_Status(DBus.Object sender, HashTable<string, Value?> status)
84     {
85         stderr.printf("NETWORK STATUS\n");
86         dump_table(status);
87
88         // dbg("cbNetworkStatus %s" % formatDict(status))
89     }
90
91     public void on_call_Status(DBus.Object sender, int index, string status, HashTable<string, Value?> properties)
92     {
93         stderr.printf("CALL STATUS %d %s\n", index, status);
94         dump_table(properties);
95         /*
96         dbg("cbCallStatus %d, %s, %s" % (id, status, formatDict(properties)))
97         self.status = status
98         if status == "incoming":
99             if "peer" in properties and properties["peer"] == "+358942832031":
100                 self.gsm_call_iface.ReleaseAll()
101                 os.system("kapula-debug-call-handler &")
102             else:
103                 os.system("alsactl restore -f /etc/alsa-scenarios/stereoout-maxvolume.state")
104                 os.system("vibrator-start")
105                 os.system("ringtone-start")
106                 os.system("ledctrl --on-time 400 --off-time 200 gta02-aux:red");
107         if status == "release":
108             os.system("ringtone-stop")
109             os.system("vibrator-stop")
110             os.system("ledctrl --off gta02-aux:red");
111         */
112     }
113
114
115 /*
116         def onIncomingUssd( self, mode, message ):
117                 logger.info( "USSD Message: %s" % message )
118                         self.main.groups["alert"].activate( "<title>Operator Message</title>%s" % message, [("OK")] )
119     def onCallStatus( self, id, status, properties ):
120         self.call = id
121         self.update_status(status)
122         if not status in ["release"]:
123             if "peer" in properties:
124                 self.part_text_set( "label", self.main.groups["contacts"].tryNumberToName( properties[ "peer" ] ) )
125                 self.part_text_set( "sublabel", properties[ "peer" ] )
126             else:
127                 self.part_text_set( "label", _("unknown number") )
128                 self.part_text_set( "sublabel", "" )
129
130     @edje.decorators.signal_callback( "mouse,clicked,1", "button_*" )
131     def on_edje_signal_dialer_button_pressed(self, emission, source):
132         key = source.split("_", 1)[1]
133         if key in ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"):
134             dbus_object.gsm_call_iface.SendDtmf( key )
135             self.text.append(key)
136         elif key in "star":
137             dbus_object.gsm_call_iface.SendDtmf( "*" )
138             self.text.append("*")
139         elif key in "hash":
140             dbus_object.gsm_call_iface.SendDtmf( "#" )
141             self.text += "#"
142         # The trailing whitespace is a workaround for the one char invisible
143         # bug due to some problems with scaling of text parts.
144         self.part_text_set("label", "".join(self.text)+" ")
145
146     @edje.decorators.signal_callback("call_button_pressed", "button_right")
147     def on_edje_signal_call_button_right_pressed(self, emission, source):
148         self.main.transition_to("call")
149
150     def sendMessage( self, index ):
151         logger.info( "trying to send message w/ index %d..." % index )
152         dbus_object.gsm_sim_iface.SendStoredMessage( index, reply_handler=self.cbSendReply, error_handler=self.cbSendError )
153
154     def cbSendReply( self, reference, timestamp ):
155         logger.info( "sent message successfully w/ reference number %d (timestamp: %s)" % ( reference, timestamp ) )
156
157     def cbSendError( self, e ):
158         logger.error( "could not send message. leaving in outgoing. error was: %s" % e )
159
160     def cbStoreReply( self, result ):
161         logger.info( "stored message lives at SIM position %d" % result )
162         self.sendMessage( result )
163         if not self.busy:
164             dbus_object.gsm_sim_iface.RetrieveMessagebook(
165                 "all",
166                 reply_handler=self.cbMessagebookReply,
167                 error_handler=self.cbMessagebookError
168             )
169             self.busy = True
170
171     def cbStoreError( self, e ):
172         logger.warning( "error while storing message - %s" % e.get_dbus_name() )
173         if e.get_dbus_name() == "org.freesmartphone.GSM.SIM.MemoryFull":
174             self.main.groups["alert"].activate( "<title>Failed to send message</title>SIM Memory Full", [("OK")] )
175
176     def cbSend1( self, selected, cb_data ):
177         self.main.groups["text_edit"].setup(
178             "sms",
179             "", # text
180             selected[0], # title
181             selected[1], # reference
182             self.cbSend2
183         )
184
185     def cbSend2( self, text, number ):
186         if dbus_object.gsm_device_obj:
187             dbus_object.gsm_sim_iface.StoreMessage(
188                 number, text, {},
189                 reply_handler=self.cbStoreReply,
190                 error_handler=self.cbStoreError
191             )
192
193     def cbDelete( self, result, reference ):
194         if result == "abort":
195             return
196         if dbus_object.gsm_device_obj:
197             dbus_object.gsm_sim_iface.DeleteMessage(
198                 reference
199             )
200         for i in range( len( self.messagebook ) ):
201             if self.messagebook[i][0] == reference:
202                 del self.messagebook[i]
203                 break
204         self.updateList()
205
206     def cbForward( self, selected, text ):
207         if dbus_object.gsm_device_obj:
208             dbus_object.gsm_sim_iface.StoreMessage(
209                 selected[1], text, {},
210                 reply_handler=self.cbStoreReply,
211                 error_handler=self.cbStoreError
212             )
213
214     def cbReply( self, text, number):
215         if dbus_object.gsm_device_obj:
216             dbus_object.gsm_sim_iface.StoreMessage(
217                 number, text, {},
218                 reply_handler=self.cbStoreReply,
219                 error_handler=self.cbStoreError
220             )
221
222     def cbMenu( self, result ):
223         if result == _("send"):
224             self.main.groups["contacts"].prepare()
225             if self.main.groups["contacts"].ready:
226                 self.main.groups["list_choose"].setup(
227                     "sms",
228                     [ (x[1], x[2]) for x in  self.main.groups["contacts"].phonebook],
229                     None,
230                     self.cbSend1
231                 )
232         elif result == _("delete"):
233             self.main.groups["alert"].activate(
234                 _("delete?"),
235                 (_("abort"), _("delete")),
236                 self.current[self.selected][0], # reference
237                 self.cbDelete
238             )
239         elif result == _("forward"):
240             self.main.groups["contacts"].prepare()
241             if self.main.groups["contacts"].ready:
242                 self.main.groups["list_choose"].setup(
243                     "sms",
244                     [ (x[1], x[2] ) for x in  self.main.groups["contacts"].phonebook],
245                     self.current[self.selected][3],
246                     self.cbForward
247                 )
248         elif result == _("reply"):
249             self.main.groups["text_edit"].setup(
250                 "sms",
251                 "", # text
252                 self.current[self.selected][2], # title = number
253                 self.current[self.selected][2], # reference = number
254                 self.cbReply
255             )
256
257     def cbMessagebookReply( self, result ):
258         logger.info( "retrieved messagebook: %s" % result )
259         self.busy = False
260         self.messagebook = result
261         self.ready = True
262         self.updateList()
263         self.main.groups["main"].targets["sms"] = True
264         self.main.groups["main"].update()
265         if not self.newindex is None:
266             message = [x for x in self.messagebook if x[0] == self.newindex]
267             self.newindex = None
268             if message and self.main.current_group == self.main.groups["main"]:
269                 message = message[0]
270                 if "read" in message[1]:
271                     from_to = _("From")
272                     timestamp = message[4]["timestamp"]
273                 else:
274                     from_to = _("To")
275                     timestamp = _("Unknown")
276                 from_text = self.main.groups["contacts"].tryNumberToName( message[2] )
277                 self.main.groups["text_show"].setup(
278                     "sms",
279                     _("%s: %s<br>Date: %s<p>%s") % (
280                         from_to,
281                         from_text,
282                         timestamp,
283                         textblock_escape( message[3] ).replace( '\n', '<br>' )
284                     )
285                 )
286             if dbus_object.gsm_device_obj:
287                 messagebookInfo = dbus_object.gsm_sim_iface.GetMessagebookInfo()
288                 if messagebookInfo["used"] == messagebookInfo["last"]:
289                     self.main.groups["alert"].activate( "<title>Warning</title>SIM Memory Full", [("OK")] )
290
291     def cbMessagebookError( self, e ):
292         logger.warning( "error while retrieving messagebook" )
293         self.busy = False
294
295     def onIncomingMessage( self, index ):
296         logger.info( "new message! Retrieving messagebook..." )
297         self.newindex = index
298         if not self.busy:
299             dbus_object.gsm_sim_iface.RetrieveMessagebook(
300                 "all",
301                 reply_handler=self.cbMessagebookReply,
302                 error_handler=self.cbMessagebookError
303             )
304             self.busy = True
305
306     def prepare( self ):
307         if not self.ready and not self.busy:
308             if dbus_object.gsm_device_obj:
309                 logger.info( "retrieving messagebook..." )
310                 dbus_object.gsm_sim_iface.RetrieveMessagebook(
311                     "all",
312                     reply_handler=self.cbMessagebookReply,
313                     error_handler=self.cbMessagebookError
314                 )
315                 self.busy = True
316             else:
317                 # Fake messagebook...
318                 self.cbMessagebookReply( [
319                     (0, "read", "+4544555", "Hello World!"),
320                     (1, "read", "+456663443", "Zhone!"),
321                     (2, "read", "+456663443", "Hi Guy\nGuess what, I now "+
322                         "know to write multi-line SMSs.\nIsn't that "+
323                         "nice?\n\nSome Buddy"),
324                     (3, "read", "Flash SMS", "An SMS without digits. Strange, isn't it?"),
325                 ] )
326
327     def onReadyStatus( self, status ):
328         logger.debug( "SIM is ready: %s" % status )
329         if status:
330             # Force update
331             self.ready = False
332             self.prepare()
333
334     def onShow( self ):
335         self.prepare()
336         self.updateList()
337
338     def updateList( self):
339         self.main.groups["contacts"].prepare()
340         self.pages = max( ( len( self.messagebook ) - 1 ) / 6 + 1, 1 )
341         if self.page >= self.pages:
342             self.page = self.pages - 1
343         if self.page < 0:
344             self.page = 0
345         self.current = self.messagebook[self.page*6:(self.page+1)*6]
346         text = u"".join( [u"□"]*self.page+[u"▣"]+[u"□"]*(self.pages-self.page-1) )
347         self.part_text_set( "pager", text )
348         for i in range( 0, len( self.current ) ):
349             main_text = self.main.groups["contacts"].tryNumberToName( self.current[i][2] )
350             self.part_text_set( "label_main_list_%i" % i, main_text )
351             sub_text = " ".join(self.current[i][3].splitlines())
352             self.part_text_set( "label_sub_list_%i" % i, u"(%s) %s" % ( self.current[i][1], sub_text ) )
353         for i in range( len( self.current ), 6):
354             self.part_text_set( "label_main_list_%i" % i, u"" )
355             self.part_text_set( "label_sub_list_%i" % i, u"" )
356         self.selected = None
357         for i in range( 6 ):
358             self.signal_emit( "deactivate_target_list_%i" % i, "" )
359
360
361     @edje.decorators.signal_callback( "mouse,clicked,1", "target_list_*" )
362     def on_edje_signal_button_list_pressed( self, emission, source ):
363         id = int( source.split( "_" )[-1] )
364         if self.selected == id:
365             return
366         if self.selected is not None:
367             self.signal_emit( "deactivate_target_list_%i" % self.selected, "" )
368         self.signal_emit( "activate_target_list_%i" % id, "" )
369         self.selected = id
370
371     @edje.decorators.signal_callback( "mouse,clicked,1", "button_action_left" )
372     def on_edje_signal_button_action_left_pressed( self, emission, source ):
373         self.page -= 1
374         self.updateList()
375
376     @edje.decorators.signal_callback( "mouse,clicked,1", "button_action_right" )
377     def on_edje_signal_button_action_right_pressed( self, emission, source ):
378         self.page += 1
379         self.updateList()
380
381     @edje.decorators.signal_callback( "mouse,clicked,1", "button_action_open" )
382     def on_edje_signal_button_action_open_pressed( self, emission, source ):
383         if self.selected is not None:
384             if "read" in self.current[self.selected][1]:
385                 from_to = _("From")
386                 timestamp = self.current[self.selected][4]["timestamp"]
387             else:
388                 from_to = _("To")
389                 timestamp = _("Unknown")
390             from_text = self.main.groups["contacts"].tryNumberToName( self.current[self.selected][2] )
391             self.main.groups["text_show"].setup(
392                 "sms",
393                 _("%s: %s<br>Date: %s<p>%s") % (
394                     from_to,
395                     from_text,
396                     timestamp,
397                     textblock_escape( self.current[self.selected][3] ).replace( '\n', '<br>' )
398                 )
399             )
400
401     @edje.decorators.signal_callback( "mouse,clicked,1", "button_bottom_middle" )
402     def on_edje_signal_button_bottom_middle_pressed( self, emission, source ):
403         self.main.groups["menu"].activate( ( _("send"), _("delete"), _("forward"), _("reply") ), self.cbMenu )
404         self.main.groups["menu"].part_text_set( "target_label_cancel", _("cancel") )
405 */
406 }
407
408 static int main (string[] args) {
409         Gtk.init (ref args);
410     // Gst.init (ref args);
411
412         // Set up zavai
413         sbus = DBus.Bus.get(DBus.BusType.SYSTEM);
414
415     // Core infrastructure
416 //      zavai.config = new zavai.Config();
417 //      zavai.config.argv0 = args[0];
418 //      zavai.registry = new zavai.Registry();
419
420     // Additional infrastructure
421         //zavai.gsm.init();
422         //zavai.log.init();
423
424     // PLAY here
425     var gr = new GSMReceive();
426
427         Gtk.main();
428
429         // zavai.info("Shutting down")
430         // zavai.registry.shutdown();
431
432         return 0;
433 }