Support for requesting contact handles (users) by name
[twitterpathy.git] / twitterpathy.rb
blob3f43054c0954a5c805f34d64f310713eaac2b62e
1 #!/usr/bin/env ruby
3 require 'rubygems'
4 gem('twitter4r', '>=0.2.1')
5 require 'twitter'
6 require 'dbus'
8 CONN_MGR_PARAM_FLAG_REQUIRED = 1
9 CONN_MGR_PARAM_FLAG_REGISTER = 2
10 CONN_MGR_PARAM_FLAG_HAS_DEFAULT = 4
11 CONN_MGR_PARAM_FLAG_SECRET = 8
13 HANDLE_TYPE_NONE = 0
14 HANDLE_TYPE_CONTACT = 1
15 HANDLE_TYPE_ROOM = 2
16 HANDLE_TYPE_LIST = 3
17 HANDLE_TYPE_GROUP = 4
19 CONNECTION_STATUS_CONNECTED = 0
20 CONNECTION_STATUS_CONNECTING = 1
21 CONNECTION_STATUS_DISCONNECTED = 2
23 CONNECTION_STATUS_REASON_NONE_SPECIFIED = 0
24 CONNECTION_STATUS_REASON_REQUESTED = 1
25 CONNECTION_STATUS_REASON_NETWORK_ERROR = 2
26 CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED = 3
27 CONNECTION_STATUS_REASON_ENCRYPTION_ERROR = 4
28 CONNECTION_STATUS_REASON_NAME_IN_USE = 5
29 CONNECTION_STATUS_REASON_CERT_NOT_PROVIDED = 6
30 CONNECTION_STATUS_REASON_CERT_UNTRUSTED = 7
31 CONNECTION_STATUS_REASON_CERT_EXPIRED = 8
32 CONNECTION_STATUS_REASON_CERT_NOT_ACTIVATED = 9
33 CONNECTION_STATUS_REASON_CERT_HOSTNAME_MISMATCH = 10
34 CONNECTION_STATUS_REASON_CERT_FINGERPRINT_MISMATCH = 11
35 CONNECTION_STATUS_REASON_CERT_SELF_SIGNED = 12
36 CONNECTION_STATUS_REASON_CERT_OTHER_ERROR = 13
38 class Twitterpathy < DBus::Object
39         dbus_interface "org.freedesktop.Telepathy.ConnectionManager" do
40                 dbus_method :GetParameters, "in proto:s, out parameters:a(susv)" do |proto|
41                         puts "GetParameters(#{proto.inspect})"
42                         $stderr.puts "Attempt to use unsupported protocol #{proto}" if proto != 'twitter'
43                         
44                         parameters = [['account', CONN_MGR_PARAM_FLAG_REQUIRED | CONN_MGR_PARAM_FLAG_REGISTER, 's', ['s', '']], ['password', CONN_MGR_PARAM_FLAG_REQUIRED | CONN_MGR_PARAM_FLAG_REGISTER | CONN_MGR_PARAM_FLAG_SECRET, 's', ['s', '']]]
45                         [parameters]
46                 end
47                 
48                 dbus_method :ListProtocols, "out protocols:as" do ||
49                         puts "ListProtocols"
50                         protocols = ['twitter']
51                         [protocols]
52                 end
53                 
54                 dbus_method :RequestConnection, "in proto:s, in parameters:a{sv}, out service:s, out object:o" do |proto, parameters|
55                         puts "RequestConnection(#{proto.inspect}, #{parameters.inspect})"
56                         $stderr.puts "Attempt to use unsupported protocol #{proto}" if proto != 'twitter'
57                         
58                         object = "/org/freedesktop/Telepathy/Connection/Twitterpathy/twitter/#{parameters['account']}"
59                         service = "org.freedesktop.Telepathy.Connection.Twitterpathy.twitter.#{parameters['account']}"
60                         
61                         #Register a new D-BUS service for this connection
62                         connection_service = $bus.request_service(service)
63                         
64                         #Create the connection object, and export it on the new service
65                         connection = TwitterConnection.new(object, parameters['account'], parameters['password'])
66                         connection_service.export(connection)
67                         
68                         #Send signal
69                         NewConnection(service, object, 'twitter')
70                         
71                         [service, object]
72                 end
73                 
74                 dbus_signal :NewConnection, 'bus_name:s, object_path:o, proto:s'
75         end
76 end
78 class TwitterConnection < DBus::Object
79         def initialize(path, account, password)
80                 puts "initialize TwitterConnection(#{path}, #{account}, ***)"
81                 @account = account
82                 @password = password
83                 @status = CONNECTION_STATUS_CONNECTING
84                 @handles = {HANDLE_TYPE_NONE => {}, HANDLE_TYPE_CONTACT => {}, HANDLE_TYPE_ROOM => {}, HANDLE_TYPE_LIST => {}, HANDLE_TYPE_GROUP => {}}
85                 super(path)
86         end
87         
88         dbus_interface 'org.freedesktop.Telepathy.Connection' do
89                 dbus_method :Connect, '' do ||
90                         puts "Connect, account=#{@account}"
91                         
92                         @twitter_client = Twitter::Client.new(:login => @account, :password => @password)
93                         
94                         @me = @twitter_client.my(:info)
95                         @handles[HANDLE_TYPE_CONTACT][@me.id] = @me
96                         
97                         puts "Connected as #{@me.inspect}"
98                         
99                         @status = CONNECTION_STATUS_CONNECTED
100                         
101                         StatusChanged(@status, CONNECTION_STATUS_REASON_REQUESTED)
102                 end
103                 
104                 dbus_method :Disconnect, '' do ||
105                         puts 'Disconnect'
106                         
107                         @status = CONNECTION_STATUS_DISCONNECTED
108                         
109                         StatusChanged(@status, CONNECTION_STATUS_REASON_REQUESTED)
110                 end
111                 
112                 dbus_method :GetInterfaces, 'out interfaces:as' do ||
113                         interfaces = []
114                         [interfaces]
115                 end
116                 
117                 dbus_method :GetProtocol, 'out protocol:s' do ||
118                         protocol = 'twitter'
119                         [protocol]
120                 end
121                 
122                 dbus_method :GetSelfHandle, 'out self_handle:u' do ||
123                         self_handle = @me.id
124                         [self_handle]
125                 end
126                 
127                 dbus_method :GetStatus, 'out status:u' do ||
128                         [@status]
129                 end
130                 
131                 dbus_method :HoldHandles, 'in handle_type:u, in handles:au' do |handle_type, handles|
132                         # TODO
133                 end
134                 
135                 dbus_method :InspectHandles, 'in handle_type:u, in handles:au, out strings:as' do |handle_type, handles|
136                         strings = handles.map{|handle| @handles[handle_type][handle].inspect }
137                         [strings]
138                 end
139                 
140                 dbus_method :ListChannels, 'out channels:a(osuu)' do ||
141                         # TODO
142                         channels = []
143                         [channels]
144                 end
145                 
146                 dbus_method :ReleaseHandles, 'in handle_type:u, in handles:au' do |handle_type, handles|
147                         # TODO
148                 end
149                 
150                 dbus_method :RequestChannel, 'in type:s, in handle_type:u, in handle:u, in suppress_handler:b, out channel:o' do |type, handle_type, handle, suppress_handler|
151                         # TODO
152                         channel = ''
153                         [channel]
154                 end
155                 
156                 dbus_method :RequestHandles, 'in handle_type:u, in names:as, out handles:au' do |handle_type, names|
157                         if handle_type == HANDLE_TYPE_CONTACT
158                                 handles = names.map {|name|
159                                         # TODO: make this more efficient?
160                                         contact_handle = nil
161                                         @handles[HANDLE_TYPE_CONTACT].each do |handle, contact|
162                                                 if contact.name == name
163                                                         contact_handle = handle
164                                                         break
165                                                 end
166                                         end
167                                         
168                                         if contact_handle.nil?
169                                                 contact = @twitter_client.user(name) # TODO: handle errors
170                                                 @handles[HANDLE_TYPE_CONTACT][contact.id] = contact
171                                                 contact_handle = contact.id
172                                         end
173                                         
174                                         contact_handle
175                                 }
176                         else
177                                 # TODO: other types
178                                 handles = []
179                         end
180                         
181                         [handles]
182                 end
183                 
184                 dbus_signal :NewChannel, 'object_path:o, channel_type:s, handle_type:u, handle:u, suppress_handler:b'
185                 dbus_signal :StatusChanged, 'status:u, reason:u'
186         end
189 $bus = DBus::SessionBus.instance
191 service = $bus.request_service("org.freedesktop.Telepathy.ConnectionManager.Twitterpathy")
193 exported_obj = Twitterpathy.new("/org/freedesktop/Telepathy/ConnectionManager/Twitterpathy")
194 service.export(exported_obj)
196 puts "listening"
197 main = DBus::Main.new
198 main << $bus
199 main.run