2 # -*- coding: utf-8 -*-
4 # Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
5 # See LICENSE.txt for copyright info
7 from __future__
import with_statement
8 from frn
.protocol
.client
import FRNClient
, FRNClientFactory
9 from frn
.user
import FRNUser
10 from twisted
.internet
import reactor
, task
11 from twisted
.internet
.defer
import DeferredList
12 from twisted
.python
import log
14 safe_chars
= string
.ascii_letters
+string
.digits
+' :;.,+-=$@'
16 PARROT_AUDIO_DELAY
= 5.0
18 def sanitizeFilename(name
):
26 class FRNParrot(FRNClient
):
28 def getClientName(self
, client_id
):
29 if self
.clientsById
.has_key(client_id
):
30 return self
.clientsById
[client_id
]['ON']
34 def textMessageReceived(self
, client
, message
, target
):
35 log
.msg("Type %s message from %s: %s" %
36 (target
, self
.getClientName(client
), message
))
37 if target
== 'P': # Only reply to private messages
38 if not message
.startswith('play'):
39 self
.sendTextMessage(client
, message
)
43 message
= sanitizeFilename(cmd
[1])
46 filename
= 'sounds/%s.wav' % message
47 if os
.path
.exists(filename
):
48 log
.msg("Streaming file %s" % filename
)
49 with
file(filename
, 'rb') as sf
:
50 sf
.seek(0x3c) # Skip wav header
56 self
.factory
.reactor
.callLater(0.5,
59 self
.sendTextMessage(client
, "File not found")
61 def stopTransmission(self
):
62 FRNClient
.stopTransmission(self
)
63 log
.msg("Stopped playback.")
65 def startRepeating(self
, from_id
):
66 log
.msg("%s stopped talking: starting playback." %
67 self
.clients
[from_id
-1]['ON'])
70 def audioFrameReceived(self
, from_id
, frames
):
71 recname
= sanitizeFilename(self
.clients
[from_id
-1]['ON'])
72 with
file('recordings/%s.gsm' % recname
, 'ab') as f
:
74 self
.feedStreaming(frames
)
76 self
.parrot_timer
.reset(PARROT_AUDIO_DELAY
)
78 log
.msg("%s started talking" %
79 self
.clients
[from_id
-1]['ON'])
80 self
.parrot_timer
= self
.factory
.reactor
.callLater(
81 PARROT_AUDIO_DELAY
, self
.startRepeating
, from_id
)
84 def loginResponse(self
, info
):
85 log
.msg("Login: %s" % info
['AL'])
87 def clientsListUpdated(self
, clients
):
88 self
.clients
= clients
89 self
.clientsById
= dict([(i
['ID'], i
) for i
in clients
])
92 class FRNParrotFactory(FRNClientFactory
):
97 if __name__
== '__main__':
99 from os
.path
import dirname
, join
as pjoin
100 from ConfigParser
import ConfigParser
102 log
.startLogging(sys
.stderr
)
104 basedir
= dirname(__file__
)
106 acfg
= ConfigParser()
107 acfg
.read(['/etc/grn/accounts.conf',
108 pjoin(basedir
,'accounts.conf'), 'accounts.conf'])
110 scfg
= ConfigParser()
111 scfg
.read(['/etc/grn/servers.conf',
112 pjoin(basedir
,'servers.conf'), 'servers.conf'])
116 server_name
, network_name
= sys
.argv
[2].split(':',1)
117 account_cfg
= acfg
.items(sys
.argv
[1])+[('network', network_name
)]
118 server_cfg
= scfg
.items(server_name
)
119 server
= scfg
.get(server_name
, 'server')
120 port
= scfg
.getint(server_name
, 'port')
122 d
= dict(account_cfg
)
125 PW
=d
['password'], ON
=d
['operator'],
126 BC
=d
['transmission'], DS
=d
['description'],
127 NN
=d
['country'], CT
=d
['city'], NT
=d
['network'])
128 reactor
.connectTCP(server
, port
, FRNParrotFactory(user
))
132 # vim: set et ai sw=4 ts=4 sts=4: