3
# ubuntuone-login - Client side log-in utility for Ubuntu One
5
# Author: Rodney Dawes <rodney.dawes@canonical.com>
7
# Copyright 2009 Canonical Ltd.
9
# This program is free software: you can redistribute it and/or modify it
10
# under the terms of the GNU General Public License version 3, as published
11
# by the Free Software Foundation.
13
# This program is distributed in the hope that it will be useful, but
14
# WITHOUT ANY WARRANTY; without even the implied warranties of
15
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
16
# PURPOSE. See the GNU General Public License for more details.
18
# You should have received a copy of the GNU General Public License along
19
# with this program. If not, see <http://www.gnu.org/licenses/>.
27
from ubuntuone import clientdefs
31
from dbus.mainloop.glib import DBusGMainLoop
32
from ubuntuone.oauthdesktop.main import Login
34
from ubuntuone.oauthdesktop.logger import setupLogging
35
logger = setupLogging("ubuntuone-login")
37
DBusGMainLoop(set_as_default=True)
40
ngettext = gettext.ngettext
42
DBUS_IFACE_AUTH_NAME = "com.ubuntuone.Authentication"
44
OAUTH_REALM = "https://ubuntuone.com"
45
OAUTH_CONSUMER = "ubuntuone"
49
# Why thank you GTK+ for enforcing style-set and breaking API
52
GtkDialog::action-area-border = 12
53
GtkDialog::button-spacing = 6
54
GtkDialog::content-area-border = 0
56
widget_class '*Dialog*' style 'dialogs'
60
class LoginMain(object):
61
"""Main login manager process class."""
63
def __init__(self, *args, **kw):
64
"""Initializes the child threads and dbus monitor."""
65
gtk.rc_parse_string(RCSTYLE)
67
logger.info(_("Starting Ubuntu One login manager version %s") %
70
self.__bus = dbus.SessionBus()
72
def _connect_dbus_signals(self):
73
"""Set up some signal handlers for DBus signals."""
74
self.__bus.add_signal_receiver(
75
handler_function=self.new_credentials,
76
signal_name="NewCredentials",
77
dbus_interface=DBUS_IFACE_AUTH_NAME)
78
self.__bus.add_signal_receiver(
79
handler_function=self.auth_denied,
80
signal_name="AuthorizationDenied",
81
dbus_interface=DBUS_IFACE_AUTH_NAME)
82
self.__bus.add_signal_receiver(
83
handler_function=self.got_oauth_error,
84
signal_name="OAuthError",
85
dbus_interface=DBUS_IFACE_AUTH_NAME)
88
def new_credentials(self, realm=None, consumer_key=None, sender=None):
89
"""Signal callback for when we get new credentials."""
90
self.set_up_desktopcouch_pairing(consumer_key)
92
def got_port(*args, **kwargs):
93
# Discard the value. We don't really care about the port, here.
96
def got_error(*args, **kwargs):
97
logger.warn("On trying to start desktopcouch-service via DBus, "
98
"we got an error. %s %s" % (args, kwargs,))
100
# We have auth, so start desktopcouch service by asking for its port.
101
dc_serv_proxy = self.__bus.get_object("org.desktopcouch.CouchDB", "/")
102
dc_serv_proxy.getPort(reply_handler=got_port, error_handler=got_error)
104
def auth_denied(self):
105
"""Signal callback for when auth was denied by user."""
106
logger.info(_("Access to Ubuntu One was denied."))
108
from twisted.internet import reactor
111
def got_oauth_error(self, message=None):
112
"""Signal callback for when an OAuth error occured."""
113
def dialog_response(dialog, response):
114
"""Handle the dialog closing."""
118
logger.error(message)
119
dialog = gtk.Dialog(title=_("Ubuntu One: Error"),
120
flags=gtk.DIALOG_NO_SEPARATOR,
121
buttons=(gtk.STOCK_CLOSE,
123
dialog.set_default_response(gtk.RESPONSE_CLOSE)
124
dialog.set_icon_name("ubuntuone-client")
126
area = dialog.get_content_area()
128
hbox = gtk.HBox(spacing=12)
129
hbox.set_border_width(12)
130
area.pack_start(hbox)
134
image.set_from_icon_name("dialog-error", gtk.ICON_SIZE_DIALOG)
135
image.set_alignment(0.5, 0.0)
137
hbox.pack_start(image, False, False)
139
vbox = gtk.VBox(spacing=12)
141
hbox.pack_start(vbox)
143
label = gtk.Label("<b>%s</b>" % _("Authorization Error"))
144
label.set_use_markup(True)
145
label.set_alignment(0.0, 0.5)
147
vbox.pack_start(label, False, False)
149
label = gtk.Label(message)
150
label.set_line_wrap(True)
151
label.set_max_width_chars(64)
152
label.set_ellipsize(pango.ELLIPSIZE_MIDDLE)
153
label.set_alignment(0.0, 0.0)
155
vbox.pack_start(label, True, True)
157
dialog.connect('close', dialog_response, gtk.RESPONSE_CLOSE)
158
dialog.connect('response', dialog_response)
162
logger.error(_("Got an OAuth error with no message."))
164
def set_up_desktopcouch_pairing(self, consumer_key):
165
"""Add a pairing record between desktopcouch and Ubuntu One"""
167
from desktopcouch.pair.couchdb_pairing.couchdb_io import \
168
put_static_paired_service
169
from desktopcouch.records.server import CouchDatabase
171
# desktopcouch is not installed
172
logger.debug(_("Not adding desktopcouch pairing since"
173
" desktopcouch is not installed"))
175
# Check whether there is already a record of the Ubuntu One service
176
db = CouchDatabase("management", create=True)
177
if not db.view_exists("ubuntu_one_pair_record","ubuntu_one_pair_record"):
178
map_js = """function(doc) {
179
if (doc.service_name == "ubuntuone") {
180
if (doc.application_annotations &&
181
doc.application_annotations["Ubuntu One"] &&
182
doc.application_annotations["Ubuntu One"]["private_application_annotations"] &&
183
doc.application_annotations["Ubuntu One"]["private_application_annotations"]["deleted"]) {
190
db.add_view("ubuntu_one_pair_record", map_js, None,
191
"ubuntu_one_pair_record")
192
results = db.execute_view("ubuntu_one_pair_record",
193
"ubuntu_one_pair_record")
195
# Results should contain either one row or no rows
196
# If there is one row, its value will be 0, meaning that there is
197
# already an Ubuntu One pairing record, or 1, meaning that there
198
# was an Ubuntu One pairing record but it has since been unpaired
199
# Only create a new record if there is not one already. Specifically,
200
# do not add the record if there is a deleted one, as this means
201
# that the user explicitly unpaired it!
205
logger.debug(_("Not adding desktopcouch pairing since"
206
" the user has explicitly unpaired with Ubuntu One"))
208
logger.debug(_("Not adding desktopcouch pairing since"
209
" we are already paired"))
211
put_static_paired_service(None, "ubuntuone")
212
logger.debug(_("Pairing desktopcouch with Ubuntu One"))
215
"""Starts the gtk main loop."""
216
self._connect_dbus_signals()
218
from twisted.internet import reactor
222
if __name__ == "__main__":
223
gettext.bindtextdomain(clientdefs.GETTEXT_PACKAGE, clientdefs.LOCALEDIR)
224
gettext.textdomain(clientdefs.GETTEXT_PACKAGE)
226
# Register DBus service for making sure we run only one instance
227
bus = dbus.SessionBus()
228
if bus.request_name(DBUS_IFACE_AUTH_NAME, dbus.bus.NAME_FLAG_DO_NOT_QUEUE) == dbus.bus.REQUEST_NAME_REPLY_EXISTS:
229
print _("Ubuntu One login manager already running, quitting")
232
from twisted.internet import gtk2reactor
233
gtk2reactor.install()
235
login = Login(dbus.service.BusName(DBUS_IFACE_AUTH_NAME,
236
bus=dbus.SessionBus()))
237
manager = LoginMain()