~ubuntu-branches/ubuntu/oneiric/ubuntuone-client/oneiric

« back to all changes in this revision

Viewing changes to ubuntuone/platform/linux/dbus_interface.py

  • Committer: Bazaar Package Importer
  • Author(s): Rodney Dawes
  • Date: 2011-02-23 18:34:09 UTC
  • mfrom: (1.1.45 upstream)
  • Revision ID: james.westby@ubuntu.com-20110223183409-535o7yo165wbjmca
Tags: 1.5.5-0ubuntu1
* New upstream release.
  - Subscribing to a RO share will not download content (LP: #712528)
  - Can't synchronize "~/Ubuntu One Music" (LP: #714976)
  - Syncdaemon needs to show progress in Unity launcher (LP: #702116)
  - Notifications say "your cloud" (LP: #715887)
  - No longer requires python-libproxy
  - Recommend unity and indicator libs by default

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
#
16
16
# You should have received a copy of the GNU General Public License along
17
17
# with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 
""" DBUS interface module """
 
18
"""DBUS interface module."""
19
19
 
20
 
import os
21
20
import dbus.service
22
21
import logging
23
 
import uuid
24
22
 
25
23
from dbus import DBusException
26
24
from xml.etree import ElementTree
30
28
from ubuntuone.platform.linux.credentials import (
31
29
    DBUS_BUS_NAME, DBUS_CREDENTIALS_PATH,
32
30
    DBUS_CREDENTIALS_IFACE)
33
 
from ubuntuone.syncdaemon.interfaces import IMarker
34
 
from ubuntuone.syncdaemon import config
35
 
from ubuntuone.syncdaemon.action_queue import Upload, Download
36
 
 
 
31
from ubuntuone.syncdaemon.interaction_interfaces import (
 
32
    bool_str,
 
33
    get_share_dict,
 
34
    get_udf_dict,
 
35
    SyncdaemonConfig,
 
36
    SyncdaemonEventListener,
 
37
    SyncdaemonEvents,
 
38
    SyncdaemonFileSystem,
 
39
    SyncdaemonFolders,
 
40
    SyncdaemonPublicFiles,
 
41
    SyncdaemonService,
 
42
    SyncdaemonShares,
 
43
    SyncdaemonStatus
 
44
)
37
45
 
38
46
# Disable the "Invalid Name" check here, as we have lots of DBus style names
39
47
# pylint: disable-msg=C0103
61
69
logger = logging.getLogger("ubuntuone.SyncDaemon.DBus")
62
70
 
63
71
 
64
 
try:
65
 
    from ubuntuone import clientdefs
66
 
    APP_NAME = clientdefs.APP_NAME
67
 
    TC_URL = clientdefs.TC_URL
68
 
    PING_URL = clientdefs.PING_URL
69
 
    DESCRIPTION = clientdefs.DESCRIPTION
70
 
except ImportError:
71
 
    APP_NAME = "Ubuntu One (ImportError mode)"
72
 
    TC_URL = "https://one.ubuntu.com/terms/"
73
 
    PING_URL = "https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/"
74
 
    DESCRIPTION = "Stub used since the real values can't be imported."
75
 
    logger.warning('Can not import APP_NAME, TC_URL, PING_URL, DESCRIPTION.'
76
 
                   'Using stub values (%s, %s, %s, %s).',
77
 
                   APP_NAME, TC_URL, PING_URL, DESCRIPTION)
78
 
 
79
 
 
80
72
class NoAccessToken(Exception):
81
73
    """The access token could not be retrieved."""
82
74
 
89
81
    """
90
82
    return thing.__class__.__name__
91
83
 
92
 
def bool_str(value):
93
 
    """Return a string value that can be converted back to bool."""
94
 
    return 'True' if value else ''
95
 
 
96
 
def _get_share_dict(share):
97
 
    """Get a dict with all the attributes of: share."""
98
 
    share_dict = share.__dict__.copy()
99
 
    if 'subscribed' not in share_dict:
100
 
        share_dict['subscribed'] = share.subscribed
101
 
    for k, v in share_dict.items():
102
 
        if v is None:
103
 
            share_dict[unicode(k)] = ''
104
 
        elif k == 'path':
105
 
            share_dict[unicode(k)] = v.decode('utf-8')
106
 
        elif k == 'accepted' or k == 'subscribed':
107
 
            share_dict[unicode(k)] = bool_str(v)
108
 
        else:
109
 
            share_dict[unicode(k)] = unicode(v)
110
 
    return share_dict
111
 
 
112
 
def _get_udf_dict(udf):
113
 
    """Get a dict with all the attributes of: udf."""
114
 
    udf_dict = udf.__dict__.copy()
115
 
    for k, v in udf_dict.items():
116
 
        if v is None:
117
 
            udf_dict[unicode(k)] = ''
118
 
        elif k == 'subscribed':
119
 
            udf_dict[unicode(k)] = bool_str(v)
120
 
        elif k == 'path':
121
 
            udf_dict[unicode(k)] = v.decode('utf-8')
122
 
        elif k == 'suggested_path' and isinstance(v, str):
123
 
            udf_dict[unicode(k)] = v.decode('utf-8')
124
 
        else:
125
 
            udf_dict[unicode(k)] = unicode(v)
126
 
    return udf_dict
127
 
 
128
84
 
129
85
class DBusExposedObject(dbus.service.Object):
130
 
    """ Base class that provides some helper methods to
131
 
    DBus exposed objects.
132
 
    """
 
86
    """Base class that provides some helper methods to DBus exposed objects."""
133
87
    #__metaclass__ = InterfaceType
134
88
 
135
89
    def __init__(self, bus_name, path):
136
 
        """ creates the instance. """
 
90
        """Create the instance."""
137
91
        dbus.service.Object.__init__(self, bus_name=bus_name,
138
92
                                     object_path=self.path)
139
93
 
140
94
    @dbus.service.signal(DBUS_IFACE_SYNC_NAME, signature='sa{ss}')
141
95
    def SignalError(self, signal, extra_args):
142
 
        """ An error ocurred while trying to emit a signal. """
 
96
        """An error ocurred while trying to emit a signal."""
143
97
 
144
98
    def emit_signal_error(self, signal, extra_args):
145
 
        """ emit's a Error signal. """
 
99
        """Emit an Error signal."""
146
100
        self.SignalError(signal, extra_args)
147
101
 
148
102
    @classmethod
149
103
    def _add_docstring(cls, func, reflection_data):
150
 
        """add <docstring> tag to reflection_data if func.__doc__ isn't None."""
 
104
        """Add <docstring> tag to reflection_data if func.__doc__ isn't None."""
151
105
        # add docstring element
152
106
        if getattr(func, '__doc__', None) is not None:
153
107
 
177
131
 
178
132
 
179
133
class Status(DBusExposedObject):
180
 
    """ Represent the status of the syncdaemon """
 
134
    """Represent the status of the syncdaemon."""
181
135
 
182
 
    def __init__(self, bus_name, dbus_iface):
183
 
        """ Creates the instance.
 
136
    def __init__(self, bus_name, dbus_iface, syncdaemon_status=None):
 
137
        """Create the instance.
184
138
 
185
139
        @param bus: the BusName of this DBusExposedObject.
186
140
        """
187
 
        self.dbus_iface = dbus_iface
188
 
        self.action_queue = dbus_iface.action_queue
189
 
        self.fs_manager = dbus_iface.fs_manager
 
141
        if not syncdaemon_status:
 
142
            syncdaemon_status = SyncdaemonStatus(dbus_iface.main,
 
143
                                                 dbus_iface.action_queue,
 
144
                                                 dbus_iface.fs_manager)
 
145
        self.syncdaemon_status = syncdaemon_status
190
146
        self.path = '/status'
191
147
        DBusExposedObject.__init__(self, bus_name=bus_name,
192
148
                                   path=self.path)
193
149
 
194
 
    def _get_current_state(self):
195
 
        """Get the current status of the system."""
196
 
        state = self.dbus_iface.main.state_manager.state
197
 
        connection = self.dbus_iface.main.state_manager.connection.state
198
 
        queues = self.dbus_iface.main.state_manager.queues.state.name
199
 
        state_dict = {
200
 
            'name': state.name,
201
 
            'description': state.description,
202
 
            'is_error': bool_str(state.is_error),
203
 
            'is_connected': bool_str(state.is_connected),
204
 
            'is_online': bool_str(state.is_online),
205
 
            'queues': queues,
206
 
            'connection': connection,
207
 
        }
208
 
        return state_dict
209
 
 
210
150
    @dbus.service.method(DBUS_IFACE_STATUS_NAME,
211
151
                         in_signature='', out_signature='a{ss}')
212
152
    def current_status(self):
213
 
        """ return the current status of the system, one of: local_rescan,
 
153
        """Return the current status of the system, one of: local_rescan,
214
154
        offline, trying_to_connect, server_rescan or online.
215
155
        """
216
156
        logger.debug('called current_status')
217
 
        return self._get_current_state()
 
157
        return self.syncdaemon_status.current_status()
218
158
 
219
159
    @dbus.service.method(DBUS_IFACE_STATUS_NAME, out_signature='aa{ss}')
220
160
    def current_downloads(self):
221
161
        """Return a list of files with a download in progress."""
222
162
        logger.debug('called current_downloads')
223
 
        current_downloads = []
224
 
        for cmd in self.action_queue.queue.waiting:
225
 
            if isinstance(cmd, Download) and cmd.running:
226
 
                entry = {
227
 
                    'path': cmd.path,
228
 
                    'share_id': cmd.share_id,
229
 
                    'node_id': cmd.node_id,
230
 
                    'n_bytes_read': str(cmd.n_bytes_read),
231
 
                }
232
 
                if cmd.deflated_size is not None:
233
 
                    entry['deflated_size'] = str(cmd.deflated_size)
234
 
                current_downloads.append(entry)
235
 
        return current_downloads
236
 
 
237
 
    def _get_command_path(self, cmd):
238
 
        """Return the path on which the command applies."""
239
 
        try:
240
 
            if IMarker.providedBy(cmd.node_id):
241
 
                # it's a marker! so it's the mdid :)
242
 
                relpath = self.fs_manager.get_by_mdid(cmd.node_id).path
243
 
            else:
244
 
                relpath = self.fs_manager.get_by_node_id(cmd.share_id,
245
 
                                                         cmd.node_id).path
246
 
            path = self.fs_manager.get_abspath(cmd.share_id, relpath)
247
 
        except KeyError:
248
 
            # probably in the trash (normal case for Unlink)
249
 
            path = ''
250
 
            key = cmd.share_id, cmd.node_id
251
 
            if key in self.fs_manager.trash:
252
 
                node_data = self.fs_manager.trash[key]
253
 
                if len(node_data) == 3:
254
 
                    # new trash!
255
 
                    path = node_data[2]
256
 
 
257
 
        return path
 
163
        return self.syncdaemon_status.current_downloads()
258
164
 
259
165
    @dbus.service.method(DBUS_IFACE_STATUS_NAME, out_signature='a(sa{ss})')
260
166
    def waiting_metadata(self):
263
169
        As we don't have meta-queue anymore, this is faked.
264
170
        """
265
171
        logger.debug('called waiting_metadata')
266
 
        waiting_metadata = []
267
 
        for cmd in self.action_queue.queue.waiting:
268
 
            if not isinstance(cmd, (Upload, Download)):
269
 
                operation = cmd.__class__.__name__
270
 
                data = cmd.to_dict()
271
 
                if 'path' not in data and hasattr(cmd, 'share_id') \
272
 
                   and hasattr(cmd, 'node_id'):
273
 
                    data['path'] = self._get_command_path(cmd)
274
 
                waiting_metadata.append((operation, data))
275
 
        return waiting_metadata
 
172
        return self.syncdaemon_status.waiting_metadata()
276
173
 
277
174
    @dbus.service.method(DBUS_IFACE_STATUS_NAME, out_signature='aa{ss}')
278
175
    def waiting_content(self):
281
178
        As we don't have content-queue anymore, this is faked.
282
179
        """
283
180
        logger.debug('called waiting_content')
284
 
        waiting_content = []
285
 
        for cmd in self.action_queue.queue.waiting:
286
 
            if isinstance(cmd, (Upload, Download)):
287
 
                path = self._get_command_path(cmd)
288
 
                data = dict(path=path, share=cmd.share_id, node=cmd.node_id,
289
 
                            operation=cmd.__class__.__name__)
290
 
                waiting_content.append(data)
291
 
        return waiting_content
 
181
        return self.syncdaemon_status.waiting_content()
292
182
 
293
183
    @dbus.service.method(DBUS_IFACE_STATUS_NAME, in_signature='ss')
294
184
    def schedule_next(self, share_id, node_id):
297
187
        queue of waiting commands.
298
188
        """
299
189
        logger.debug('called schedule_next')
300
 
        self.action_queue.content_queue.schedule_next(share_id, node_id)
 
190
        self.syncdaemon_status.schedule_next(share_id, node_id)
301
191
 
302
192
    @dbus.service.method(DBUS_IFACE_STATUS_NAME, out_signature='aa{ss}')
303
193
    def current_uploads(self):
304
 
        """ return a list of files with a upload in progress """
 
194
        """Return a list of files with a upload in progress."""
305
195
        logger.debug('called current_uploads')
306
 
        current_uploads = []
307
 
        for cmd in self.action_queue.queue.waiting:
308
 
            if isinstance(cmd, Upload) and cmd.running:
309
 
                entry = {
310
 
                    'path': cmd.path,
311
 
                    'share_id': cmd.share_id,
312
 
                    'node_id': cmd.node_id,
313
 
                    'n_bytes_written': str(cmd.n_bytes_written),
314
 
                }
315
 
                if cmd.deflated_size is not None:
316
 
                    entry['deflated_size'] = str(cmd.deflated_size)
317
 
                current_uploads.append(entry)
318
 
        return current_uploads
 
196
        return self.syncdaemon_status.current_uploads()
319
197
 
320
198
    @dbus.service.signal(DBUS_IFACE_STATUS_NAME)
321
199
    def DownloadStarted(self, path):
383
261
 
384
262
    def emit_status_changed(self, state):
385
263
        """Emit StatusChanged."""
386
 
        self.StatusChanged(self._get_current_state())
 
264
        self.StatusChanged(self.syncdaemon_status.current_status())
387
265
 
388
266
    def emit_download_started(self, download):
389
267
        """Emit DownloadStarted."""
434
312
    @param event_queue: the Event Queue
435
313
    """
436
314
    def __init__(self, bus_name, event_queue):
437
 
        self.event_queue = event_queue
 
315
        self.events = SyncdaemonEvents(event_queue)
438
316
        self.path = '/events'
439
317
        DBusExposedObject.__init__(self, bus_name=bus_name,
440
318
                                   path=self.path)
455
333
    def push_event(self, event_name, args):
456
334
        """Push an event to the event queue."""
457
335
        logger.debug('push_event: %r with %r', event_name, args)
458
 
        str_args = dict((str(k), str(v)) for k, v in args.items())
459
 
        self.event_queue.push(str(event_name), **str_args)
 
336
        self.events.push_event(event_name, args)
460
337
 
461
338
 
462
339
class AllEventsSender(object):
472
349
        self.dbus_iface.events.emit_event(event_dict)
473
350
 
474
351
 
475
 
class EventListener(object):
476
 
    """An Event Queue Listener."""
477
 
 
478
 
    def __init__(self, dbus_iface):
479
 
        self.dbus_iface = dbus_iface
480
 
 
481
 
    def handle_AQ_DOWNLOAD_STARTED(self, share_id, node_id, server_hash):
482
 
        """Handle AQ_DOWNLOAD_STARTED."""
483
 
        try:
484
 
            mdobj = self.dbus_iface.fs_manager.get_by_node_id(share_id, node_id)
485
 
            if mdobj.is_dir:
486
 
                return
487
 
            path = self.dbus_iface.fs_manager.get_abspath(share_id, mdobj.path)
488
 
            self.dbus_iface.status.emit_download_started(path)
489
 
        except KeyError, e:
490
 
            args = dict(message='The md is gone before sending '
491
 
                        'DownloadStarted signal',
492
 
                        error=str(e),
493
 
                        share_id=str(share_id),
494
 
                        node_id=str(node_id))
495
 
            self.dbus_iface.status.emit_signal_error('DownloadStarted', args)
496
 
 
497
 
    def handle_AQ_DOWNLOAD_FILE_PROGRESS(self, share_id, node_id,
498
 
                                         n_bytes_read, deflated_size):
499
 
        """Handle AQ_DOWNLOAD_FILE_PROGRESS."""
500
 
        try:
501
 
            mdobj = self.dbus_iface.fs_manager.get_by_node_id(share_id, node_id)
502
 
        except KeyError, e:
503
 
            args = dict(message='The md is gone before sending '
504
 
                        'DownloadFileProgress signal',
505
 
                        error=str(e),
506
 
                        share_id=str(share_id),
507
 
                        node_id=str(node_id))
508
 
            self.dbus_iface.status.emit_signal_error('DownloadFileProgress',
509
 
                                                     args)
510
 
        else:
511
 
            path = self.dbus_iface.fs_manager.get_abspath(share_id, mdobj.path)
512
 
            self.dbus_iface.status.emit_download_file_progress(path,
513
 
                                                 n_bytes_read=n_bytes_read,
514
 
                                                 deflated_size=deflated_size
515
 
                                                               )
516
 
 
517
 
    def handle_AQ_DOWNLOAD_FINISHED(self, share_id, node_id, server_hash):
518
 
        """Handle AQ_DOWNLOAD_FINISHED."""
519
 
        try:
520
 
            mdobj = self.dbus_iface.fs_manager.get_by_node_id(share_id, node_id)
521
 
            if mdobj.is_dir:
522
 
                return
523
 
            path = self.dbus_iface.fs_manager.get_abspath(share_id, mdobj.path)
524
 
            self.dbus_iface.status.emit_download_finished(path)
525
 
        except KeyError, e:
526
 
            # file is gone before we got this
527
 
            args = dict(message='The md is gone before sending '
528
 
                        'DownloadFinished signal',
529
 
                        error=str(e),
530
 
                        share_id=str(share_id),
531
 
                        node_id=str(node_id))
532
 
            self.dbus_iface.status.emit_signal_error('DownloadFinished', args)
533
 
 
534
 
    def handle_AQ_DOWNLOAD_CANCELLED(self, share_id, node_id, server_hash):
535
 
        """Handle AQ_DOWNLOAD_CANCELLED."""
536
 
        self.handle_AQ_DOWNLOAD_ERROR(share_id, node_id, server_hash,
537
 
                                      'CANCELLED', 'AQ_DOWNLOAD_CANCELLED')
538
 
 
539
 
    def handle_AQ_DOWNLOAD_ERROR(self, share_id, node_id, server_hash, error,
540
 
                                 event='AQ_DOWNLOAD_ERROR'):
541
 
        """Handle AQ_DOWNLOAD_ERROR."""
542
 
        try:
543
 
            mdobj = self.dbus_iface.fs_manager.get_by_node_id(share_id, node_id)
544
 
            if mdobj.is_dir:
545
 
                return
546
 
            path = self.dbus_iface.fs_manager.get_abspath(share_id, mdobj.path)
547
 
            self.dbus_iface.status.emit_download_finished(path, error=error)
548
 
        except KeyError, e:
549
 
            # file is gone before we got this
550
 
            args = dict(message='The md is gone before sending '
551
 
                        'DownloadFinished signal',
552
 
                        error=str(e),
553
 
                        share_id=str(share_id),
554
 
                        node_id=str(node_id),
555
 
                        download_error=str(error))
556
 
            self.dbus_iface.status.emit_signal_error('DownloadFinished', args)
557
 
 
558
 
    def handle_AQ_UPLOAD_STARTED(self, share_id, node_id, hash):
559
 
        """Handle AQ_UPLOAD_STARTED."""
560
 
        try:
561
 
            mdobj = self.dbus_iface.fs_manager.get_by_node_id(share_id, node_id)
562
 
            if mdobj.is_dir:
563
 
                return
564
 
            path = self.dbus_iface.fs_manager.get_abspath(share_id, mdobj.path)
565
 
            self.dbus_iface.status.emit_upload_started(path)
566
 
        except KeyError, e:
567
 
            args = dict(message='The md is gone before sending '
568
 
                        'UploadStarted signal',
569
 
                        error=str(e),
570
 
                        share_id=str(share_id),
571
 
                        node_id=str(node_id))
572
 
            self.dbus_iface.status.emit_signal_error('UploadStarted', args)
573
 
 
574
 
    def handle_AQ_UPLOAD_FILE_PROGRESS(self, share_id, node_id,
575
 
                                         n_bytes_written, deflated_size):
576
 
        """Handle AQ_UPLOAD_FILE_PROGRESS."""
577
 
        try:
578
 
            mdobj = self.dbus_iface.fs_manager.get_by_node_id(share_id, node_id)
579
 
        except KeyError, e:
580
 
            args = dict(message='The md is gone before sending '
581
 
                        'UploadFileProgress signal',
582
 
                        error=str(e),
583
 
                        share_id=str(share_id),
584
 
                        node_id=str(node_id))
585
 
            self.dbus_iface.status.emit_signal_error('UploadFileProgress',
586
 
                                                     args)
587
 
        else:
588
 
            path = self.dbus_iface.fs_manager.get_abspath(share_id, mdobj.path)
589
 
            self.dbus_iface.status.emit_upload_file_progress(path,
590
 
                                                n_bytes_written=n_bytes_written,
591
 
                                                deflated_size=deflated_size
592
 
                                                             )
593
 
 
594
 
    def handle_AQ_UPLOAD_FINISHED(self, share_id, node_id, hash,
595
 
                                  new_generation):
596
 
        """Handle AQ_UPLOAD_FINISHED."""
597
 
        try:
598
 
            mdobj = self.dbus_iface.fs_manager.get_by_node_id(share_id,
599
 
                                                              node_id)
600
 
            if mdobj.is_dir:
601
 
                return
602
 
            path = self.dbus_iface.fs_manager.get_abspath(share_id, mdobj.path)
603
 
            self.dbus_iface.status.emit_upload_finished(path)
604
 
        except KeyError, e:
605
 
            # file is gone before we got this
606
 
            args = dict(message='The metadata is gone before sending '
607
 
                        'UploadFinished signal',
608
 
                        error=str(e),
609
 
                        share_id=str(share_id),
610
 
                        node_id=str(node_id))
611
 
            self.dbus_iface.status.emit_signal_error('UploadFinished', args)
612
 
 
613
 
    def handle_SV_ACCOUNT_CHANGED(self, account_info):
614
 
        """Handle SV_ACCOUNT_CHANGED."""
615
 
        self.dbus_iface.status.emit_account_changed(account_info)
616
 
 
617
 
    def handle_AQ_UPLOAD_ERROR(self, share_id, node_id, error, hash):
618
 
        """Handle AQ_UPLOAD_ERROR."""
619
 
        try:
620
 
            mdobj = self.dbus_iface.fs_manager.get_by_node_id(share_id, node_id)
621
 
            if mdobj.is_dir:
622
 
                return
623
 
            path = self.dbus_iface.fs_manager.get_abspath(share_id, mdobj.path)
624
 
            self.dbus_iface.status.emit_upload_finished(path, error=error)
625
 
        except KeyError, e:
626
 
            # file is gone before we got this
627
 
            args = dict(message='The metadata is gone before sending '
628
 
                        'UploadFinished signal',
629
 
                        error=str(e),
630
 
                        share_id=str(share_id),
631
 
                        node_id=str(node_id),
632
 
                        upload_error=str(error))
633
 
            self.dbus_iface.status.emit_signal_error('UploadFinished', args)
634
 
 
635
 
    def handle_FS_INVALID_NAME(self, dirname, filename):
636
 
        """Handle FS_INVALID_NAME."""
637
 
        self.dbus_iface.status.emit_invalid_name(dirname, filename)
638
 
 
639
 
    def handle_SYS_BROKEN_NODE(self, volume_id, node_id, mdid, path):
640
 
        """Handle SYS_BROKEN_NODE."""
641
 
        self.dbus_iface.status.emit_broken_node(volume_id, node_id, mdid, path)
642
 
 
643
 
    def handle_SYS_STATE_CHANGED(self, state):
644
 
        """Handle SYS_STATE_CHANGED."""
645
 
        self.dbus_iface.status.emit_status_changed(state)
646
 
 
647
 
    def handle_SV_FREE_SPACE(self, share_id, free_bytes):
648
 
        """Handle SV_FREE_SPACE event, emit ShareChanged signal."""
649
 
        self.dbus_iface.shares.emit_free_space(share_id, free_bytes)
650
 
 
651
 
    def handle_AQ_CREATE_SHARE_OK(self, share_id, marker):
652
 
        """Handle AQ_CREATE_SHARE_OK event, emit ShareCreated signal."""
653
 
        share = self.dbus_iface.volume_manager.shared.get(str(share_id))
654
 
        share_dict = {}
655
 
        if share:
656
 
            # pylint: disable-msg=W0212
657
 
            share_dict.update(_get_share_dict(share))
658
 
        else:
659
 
            share_dict.update(dict(volume_id=str(share_id)))
660
 
        self.dbus_iface.shares.emit_share_created(share_dict)
661
 
 
662
 
    def handle_AQ_CREATE_SHARE_ERROR(self, marker, error):
663
 
        """Handle AQ_CREATE_SHARE_ERROR event, emit ShareCreateError signal."""
664
 
        self.dbus_iface.shares.emit_share_create_error(dict(marker=marker),
665
 
                                                       error)
666
 
 
667
 
    def handle_AQ_ANSWER_SHARE_OK(self, share_id, answer):
668
 
        """ handle AQ_ANSWER_SHARE_OK event, emit ShareAnswerOk signal. """
669
 
        self.dbus_iface.shares.emit_share_answer_response(str(share_id), answer)
670
 
 
671
 
    def handle_AQ_ANSWER_SHARE_ERROR(self, share_id, answer, error):
672
 
        """Handle AQ_ANSWER_SHARE_ERROR event, emit ShareAnswerError signal."""
673
 
        self.dbus_iface.shares.emit_share_answer_response(str(share_id), answer,
674
 
                                                          error)
675
 
    def handle_VM_UDF_SUBSCRIBED(self, udf):
676
 
        """Handle VM_UDF_SUBSCRIBED event, emit FolderSubscribed signal."""
677
 
        self.dbus_iface.folders.emit_folder_subscribed(udf)
678
 
 
679
 
    def handle_VM_UDF_SUBSCRIBE_ERROR(self, udf_id, error):
680
 
        """Handle VM_UDF_SUBSCRIBE_ERROR, emit FolderSubscribeError signal."""
681
 
        self.dbus_iface.folders.emit_folder_subscribe_error(udf_id, error)
682
 
 
683
 
    def handle_VM_UDF_UNSUBSCRIBED(self, udf):
684
 
        """Handle VM_UDF_UNSUBSCRIBED event, emit FolderUnSubscribed signal."""
685
 
        self.dbus_iface.folders.emit_folder_unsubscribed(udf)
686
 
 
687
 
    def handle_VM_UDF_UNSUBSCRIBE_ERROR(self, udf_id, error):
688
 
        """Handle VM_UDF_UNSUBSCRIBE_ERROR, emit FolderUnSubscribeError."""
689
 
        self.dbus_iface.folders.emit_folder_unsubscribe_error(udf_id, error)
690
 
 
691
 
    def handle_VM_UDF_CREATED(self, udf):
692
 
        """Handle VM_UDF_CREATED event, emit FolderCreated signal."""
693
 
        self.dbus_iface.folders.emit_folder_created(udf)
694
 
 
695
 
    def handle_VM_UDF_CREATE_ERROR(self, path, error):
696
 
        """Handle VM_UDF_CREATE_ERROR event, emit FolderCreateError signal."""
697
 
        self.dbus_iface.folders.emit_folder_create_error(path, error)
698
 
 
699
 
    def handle_VM_SHARE_SUBSCRIBED(self, share):
700
 
        """Handle VM_SHARE_SUBSCRIBED event, emit ShareSubscribed signal."""
701
 
        self.dbus_iface.shares.emit_share_subscribed(share)
702
 
 
703
 
    def handle_VM_SHARE_SUBSCRIBE_ERROR(self, share_id, error):
704
 
        """Handle VM_SHARE_SUBSCRIBE_ERROR, emit ShareSubscribeError signal."""
705
 
        self.dbus_iface.shares.emit_share_subscribe_error(share_id, error)
706
 
 
707
 
    def handle_VM_SHARE_UNSUBSCRIBED(self, share):
708
 
        """Handle VM_SHARE_UNSUBSCRIBED event, emit ShareUnSubscribed."""
709
 
        self.dbus_iface.shares.emit_share_unsubscribed(share)
710
 
 
711
 
    def handle_VM_SHARE_UNSUBSCRIBE_ERROR(self, share_id, error):
712
 
        """Handle VM_SHARE_UNSUBSCRIBE_ERROR, emit ShareUnSubscribeError."""
713
 
        self.dbus_iface.shares.emit_share_unsubscribe_error(share_id, error)
714
 
 
715
 
    def handle_VM_SHARE_CREATED(self, share_id):
716
 
        """Handle VM_SHARE_CREATED event, emit NewShare event."""
717
 
        self.dbus_iface.shares.emit_new_share(share_id)
718
 
 
719
 
    def handle_VM_SHARE_DELETED(self, share):
720
 
        """Handle VM_SHARE_DELETED event, emit NewShare event."""
721
 
        self.dbus_iface.shares.emit_share_changed('deleted', share)
722
 
 
723
 
    def handle_VM_SHARE_DELETE_ERROR(self, share_id, error):
724
 
        """Handle VM_DELETE_SHARE_ERROR event, emit ShareCreateError signal."""
725
 
        self.dbus_iface.shares.ShareDeleteError(dict(volume_id=share_id), error)
726
 
 
727
 
    def handle_VM_VOLUME_DELETED(self, volume):
728
 
        """Handle VM_VOLUME_DELETED event.
729
 
 
730
 
        Emits FolderDeleted or ShareChanged signal.
731
 
 
732
 
        """
733
 
        from ubuntuone.syncdaemon.volume_manager import Share, UDF
734
 
 
735
 
        if isinstance(volume, Share):
736
 
            self.dbus_iface.shares.emit_share_changed('deleted', volume)
737
 
        elif isinstance(volume, UDF):
738
 
            self.dbus_iface.folders.emit_folder_deleted(volume)
739
 
        else:
740
 
            logger.error("Unable to handle VM_VOLUME_DELETE for "
741
 
                     "volume_id=%r as it's not a share or UDF", volume.id)
742
 
 
743
 
    def handle_VM_VOLUME_DELETE_ERROR(self, volume_id, error):
744
 
        """Handle VM_VOLUME_DELETE_ERROR event, emit ShareDeleted event."""
745
 
        from ubuntuone.syncdaemon.volume_manager import Share, UDF, \
746
 
            VolumeDoesNotExist
747
 
 
748
 
        try:
749
 
            volume = self.dbus_iface.volume_manager.get_volume(volume_id)
750
 
        except VolumeDoesNotExist:
751
 
            logger.error("Unable to handle VM_VOLUME_DELETE_ERROR for "
752
 
                         "volume_id=%r, no such volume.", volume_id)
753
 
        else:
754
 
            if isinstance(volume, Share):
755
 
                self.dbus_iface.shares.emit_share_delete_error(volume, error)
756
 
            elif isinstance(volume, UDF):
757
 
                self.dbus_iface.folders.emit_folder_delete_error(volume, error)
758
 
            else:
759
 
                logger.error("Unable to handle VM_VOLUME_DELETE_ERROR for "
760
 
                         "volume_id=%r as it's not a share or UDF", volume_id)
761
 
 
762
 
    def handle_VM_SHARE_CHANGED(self, share_id):
763
 
        """ handle VM_SHARE_CHANGED event, emit's ShareChanged signal. """
764
 
        share = self.dbus_iface.volume_manager.shares.get(share_id)
765
 
        self.dbus_iface.shares.emit_share_changed('changed', share)
766
 
 
767
 
    def handle_AQ_CHANGE_PUBLIC_ACCESS_OK(self, share_id, node_id,
768
 
                                          is_public, public_url):
769
 
        """Handle the AQ_CHANGE_PUBLIC_ACCESS_OK event."""
770
 
        self.dbus_iface.public_files.emit_public_access_changed(
771
 
            share_id, node_id, is_public, public_url)
772
 
 
773
 
    def handle_AQ_CHANGE_PUBLIC_ACCESS_ERROR(self, share_id, node_id, error):
774
 
        """Handle the AQ_CHANGE_PUBLIC_ACCESS_ERROR event."""
775
 
        self.dbus_iface.public_files.emit_public_access_change_error(
776
 
            share_id, node_id, error)
777
 
 
778
 
    def handle_SYS_ROOT_MISMATCH(self, root_id, new_root_id):
779
 
        """Handle the SYS_ROOT_MISMATCH event."""
780
 
        self.dbus_iface.sync.emit_root_mismatch(root_id, new_root_id)
781
 
 
782
 
    def handle_AQ_PUBLIC_FILES_LIST_OK(self, public_files):
783
 
        """Handle the AQ_PUBLIC_FILES_LIST_OK event."""
784
 
        self.dbus_iface.public_files.emit_public_files_list(public_files)
785
 
 
786
 
    def handle_AQ_PUBLIC_FILES_LIST_ERROR(self, error):
787
 
        """Handle the AQ_PUBLIC_FILES_LIST_ERROR event."""
788
 
        self.dbus_iface.public_files.emit_public_files_list_error(error)
789
 
 
790
 
    def handle_SYS_QUOTA_EXCEEDED(self, volume_id, free_bytes):
791
 
        """Handle the SYS_QUOTA_EXCEEDED event."""
792
 
        from ubuntuone.syncdaemon.volume_manager import UDF
793
 
 
794
 
        volume = self.dbus_iface.volume_manager.get_volume(str(volume_id))
795
 
 
796
 
        volume_dict = {}
797
 
        if isinstance(volume, UDF):
798
 
            volume_dict = _get_udf_dict(volume)
799
 
        else:
800
 
            # either a Share or Root
801
 
            volume_dict = _get_share_dict(volume)
802
 
 
803
 
        # be sure that the volume has the most updated free bytes info
804
 
        volume_dict['free_bytes'] = str(free_bytes)
805
 
 
806
 
        self.dbus_iface.sync.emit_quota_exceeded(volume_dict)
807
 
 
808
 
    def handle_SYS_QUEUE_ADDED(self, command):
809
 
        """Handle SYS_QUEUE_ADDED."""
810
 
        if isinstance(command, (Upload, Download)):
811
 
            self.dbus_iface.status.emit_content_queue_changed()
812
 
        else:
813
 
            self.dbus_iface.status.emit_metaqueue_changed()
814
 
 
815
 
    def handle_SYS_QUEUE_REMOVED(self, command):
816
 
        """Handle SYS_QUEUE_REMOVED."""
817
 
        self.handle_SYS_QUEUE_ADDED(command)
818
 
 
819
 
 
820
352
class SyncDaemon(DBusExposedObject):
821
 
    """ The Daemon dbus interface. """
 
353
    """The Daemon dbus interface."""
822
354
 
823
355
    def __init__(self, bus_name, dbus_iface):
824
 
        """ Creates the instance.
 
356
        """Create the instance.
825
357
 
826
358
        @param bus: the BusName of this DBusExposedObject.
827
359
        """
828
360
        self.dbus_iface = dbus_iface
 
361
        self.service = SyncdaemonService(dbus_iface, dbus_iface.main,
 
362
                                         dbus_iface.volume_manager,
 
363
                                         dbus_iface.action_queue)
829
364
        self.path = '/'
830
365
        DBusExposedObject.__init__(self, bus_name=bus_name,
831
366
                                   path=self.path)
833
368
    @dbus.service.method(DBUS_IFACE_SYNC_NAME,
834
369
                         in_signature='', out_signature='')
835
370
    def connect(self):
836
 
        """ Connect to the server. """
 
371
        """Connect to the server."""
837
372
        logger.debug('connect requested')
838
 
        self.dbus_iface.connect()
 
373
        self.service.connect()
839
374
 
840
375
    @dbus.service.method(DBUS_IFACE_SYNC_NAME,
841
376
                         in_signature='', out_signature='')
842
377
    def disconnect(self):
843
 
        """ Disconnect from the server. """
 
378
        """Disconnect from the server."""
844
379
        logger.debug('disconnect requested')
845
 
        self.dbus_iface.disconnect()
 
380
        self.service.disconnect()
846
381
 
847
382
    @dbus.service.method(DBUS_IFACE_SYNC_NAME,
848
383
                         in_signature='', out_signature='s')
849
384
    def get_rootdir(self):
850
 
        """ Returns the root dir/mount point. """
 
385
        """Return the root dir/mount point."""
851
386
        logger.debug('called get_rootdir')
852
 
        return self.dbus_iface.main.get_rootdir()
 
387
        return self.service.get_rootdir()
853
388
 
854
389
    @dbus.service.method(DBUS_IFACE_SYNC_NAME,
855
390
                         in_signature='', out_signature='s')
856
391
    def get_sharesdir(self):
857
 
        """ Returns the shares dir/mount point. """
 
392
        """Return the shares dir/mount point."""
858
393
        logger.debug('called get_sharesdir')
859
 
        return self.dbus_iface.main.get_sharesdir()
 
394
        return self.service.get_sharesdir()
860
395
 
861
396
    @dbus.service.method(DBUS_IFACE_SYNC_NAME,
862
397
                         in_signature='', out_signature='s')
863
398
    def get_sharesdir_link(self):
864
 
        """ Returns the shares dir/mount point. """
 
399
        """Return the shares dir/mount point."""
865
400
        logger.debug('called get_sharesdir_link')
866
 
        return self.dbus_iface.main.get_sharesdir_link()
 
401
        return self.service.get_sharesdir_link()
867
402
 
868
403
    @dbus.service.method(DBUS_IFACE_SYNC_NAME,
869
404
                         in_signature='d', out_signature='b',
870
405
                         async_callbacks=('reply_handler', 'error_handler'))
871
406
    def wait_for_nirvana(self, last_event_interval,
872
407
                         reply_handler=None, error_handler=None):
873
 
        """ call the reply handler when there are no more
 
408
        """Call the reply handler when there are no more
874
409
        events or transfers.
875
410
        """
876
411
        logger.debug('called wait_for_nirvana')
877
 
        d = self.dbus_iface.main.wait_for_nirvana(last_event_interval)
878
 
        d.addCallbacks(reply_handler, error_handler)
879
 
        return d
 
412
        return self.service.wait_for_nirvana(last_event_interval,
 
413
                                             reply_handler, error_handler)
880
414
 
881
415
    @dbus.service.method(DBUS_IFACE_SYNC_NAME,
882
416
                         in_signature='', out_signature='',
883
417
                         async_callbacks=('reply_handler', 'error_handler'))
884
418
    def quit(self, reply_handler=None, error_handler=None):
885
 
        """ shutdown the syncdaemon. """
 
419
        """Shutdown the syncdaemon."""
886
420
        logger.debug('Quit requested')
887
 
        if reply_handler:
888
 
            reply_handler()
889
 
        self.dbus_iface.quit()
 
421
        self.service.quit(reply_handler, error_handler)
890
422
 
891
423
    @dbus.service.method(DBUS_IFACE_SYNC_NAME,
892
424
                         in_signature='s', out_signature='')
893
425
    def rescan_from_scratch(self, volume_id):
894
426
        """Request a rescan from scratch of the volume with volume_id."""
895
 
        # check that the volume exists
896
 
        volume = self.dbus_iface.volume_manager.get_volume(str(volume_id))
897
 
        self.dbus_iface.action_queue.rescan_from_scratch(volume.volume_id)
 
427
        self.service.rescan_from_scratch(volume_id)
898
428
 
899
429
    @dbus.service.signal(DBUS_IFACE_SYNC_NAME,
900
430
                         signature='ss')
916
446
 
917
447
 
918
448
class FileSystem(DBusExposedObject):
919
 
    """ A dbus interface to the FileSystem Manager. """
 
449
    """A dbus interface to the FileSystem Manager."""
920
450
 
921
451
    def __init__(self, bus_name, fs_manager, action_queue):
922
 
        """ Creates the instance. """
923
 
        self.fs_manager = fs_manager
924
 
        self.action_queue = action_queue
 
452
        """Create the instance."""
 
453
        self.syncdaemon_filesystem = SyncdaemonFileSystem(fs_manager,
 
454
                                                          action_queue)
925
455
        self.path = '/filesystem'
926
456
        DBusExposedObject.__init__(self, bus_name=bus_name,
927
457
                                   path=self.path)
931
461
    def get_metadata(self, path):
932
462
        """Return the metadata (as a dict) for the specified path."""
933
463
        logger.debug('get_metadata by path: %r', path)
934
 
        real_path = os.path.realpath(path.encode('utf-8'))
935
 
        mdobj = self.fs_manager.get_by_path(real_path)
936
 
        md_dict = self._mdobj_dict(mdobj)
937
 
        md_dict['path'] = path
938
 
        return md_dict
 
464
        return self.syncdaemon_filesystem.get_metadata(path)
939
465
 
940
466
    @dbus.service.method(DBUS_IFACE_FS_NAME,
941
467
                         in_signature='ss', out_signature='a{ss}')
942
468
    def get_metadata_by_node(self, share_id, node_id):
943
469
        """Return the metadata (as a dict) for the specified share/node."""
944
470
        logger.debug('get_metadata by share: %r  node: %r', share_id, node_id)
945
 
        mdobj = self.fs_manager.get_by_node_id(share_id, node_id)
946
 
        md_dict = self._mdobj_dict(mdobj)
947
 
        path = self.fs_manager.get_abspath(mdobj.share_id, mdobj.path)
948
 
        md_dict['path'] = path
949
 
        return md_dict
 
471
        return self.syncdaemon_filesystem.get_metadata_by_node(share_id,
 
472
                                                               node_id)
950
473
 
951
474
    @dbus.service.method(DBUS_IFACE_FS_NAME,
952
475
                         in_signature='s', out_signature='a{ss}')
953
476
    def get_metadata_and_quick_tree_synced(self, path):
954
 
        """ returns the dict with the attributes of the metadata for
 
477
        """Return the dict with the attributes of the metadata for
955
478
        the specified path, including the quick subtree status.
956
479
        """
957
480
        logger.debug('get_metadata_and_quick_tree_synced: %r', path)
958
 
        real_path = os.path.realpath(path.encode('utf-8'))
959
 
        mdobj = self.fs_manager.get_by_path(real_path)
960
 
        md_dict = self._mdobj_dict(mdobj)
961
 
        md_dict['path'] = path
962
 
        if self._path_in_queue(real_path):
963
 
            md_dict['quick_tree_synced'] = ''
964
 
        else:
965
 
            md_dict['quick_tree_synced'] = 'synced'
966
 
        return md_dict
967
 
 
968
 
    def _path_in_queue(self, path):
969
 
        """Return whether there are queued commands pertaining to the path."""
970
 
        for cmd in self.action_queue.queue.waiting:
971
 
            share_id = getattr(cmd, 'share_id', None)
972
 
            node_id = getattr(cmd, 'node_id', None)
973
 
            if share_id is not None and node_id is not None:
974
 
                # XXX: nested try/excepts in a loop are probably a
975
 
                # sign that I'm doing something wrong - or that
976
 
                # somebody is :)
977
 
                this_path = ''
978
 
                try:
979
 
                    node_md = self.fs_manager.get_by_node_id(share_id, node_id)
980
 
                except KeyError:
981
 
                    # maybe it's actually the mdid?
982
 
                    try:
983
 
                        node_md = self.fs_manager.get_by_mdid(node_id)
984
 
                    except KeyError:
985
 
                        # hm, nope. Dunno what to do then
986
 
                        pass
987
 
                    else:
988
 
                        this_path = self.fs_manager.get_abspath(share_id,
989
 
                                                                node_md.path)
990
 
                else:
991
 
                    this_path = self.fs_manager.get_abspath(share_id,
992
 
                                                            node_md.path)
993
 
                if this_path.startswith(path):
994
 
                    return True
995
 
        return False
996
 
 
997
 
    def _mdobj_dict(self, mdobj):
998
 
        """Returns a dict from a MDObject."""
999
 
        md_dict = {}
1000
 
        for k, v in mdobj.__dict__.items():
1001
 
            if k == 'info':
1002
 
                continue
1003
 
            elif k == 'path':
1004
 
                md_dict[str(k)] = v.decode('utf-8')
1005
 
            else:
1006
 
                md_dict[str(k)] = str(v)
1007
 
        if mdobj.__dict__.get('info', None):
1008
 
            for k, v in mdobj.info.__dict__.items():
1009
 
                md_dict['info_'+str(k)] = str(v)
1010
 
        return md_dict
 
481
        return self.syncdaemon_filesystem.get_metadata_and_quick_tree_synced(
 
482
                                                                        path)
 
483
 
1011
484
 
1012
485
    @dbus.service.method(DBUS_IFACE_FS_NAME,
1013
486
                         in_signature='', out_signature='aa{ss}')
1014
487
    def get_dirty_nodes(self):
1015
488
        """Rerturn a list of dirty nodes."""
1016
 
        mdobjs = self.fs_manager.get_dirty_nodes()
1017
 
        dirty_nodes = []
1018
 
        for mdobj in mdobjs:
1019
 
            dirty_nodes.append(self._mdobj_dict(mdobj))
1020
 
        return dirty_nodes
 
489
        return self.syncdaemon_filesystem.get_dirty_nodes()
1021
490
 
1022
491
 
1023
492
class Shares(DBusExposedObject):
1025
494
 
1026
495
    def __init__(self, bus_name, fs_manager, volume_manager):
1027
496
        """Create the instance."""
1028
 
        self.fs_manager = fs_manager
1029
 
        self.vm = volume_manager
 
497
        self.syncdaemon_shares = SyncdaemonShares(fs_manager, volume_manager)
1030
498
        self.path = '/shares'
1031
499
        DBusExposedObject.__init__(self, bus_name=bus_name,
1032
500
                                   path=self.path)
1036
504
    def get_shares(self):
1037
505
        """Return a list of dicts, each dict represents a share."""
1038
506
        logger.debug('called get_shares')
1039
 
        shares = []
1040
 
        for share_id, share in self.vm.shares.items():
1041
 
            if share_id == '':
1042
 
                continue
1043
 
            share_dict = _get_share_dict(share)
1044
 
            shares.append(share_dict)
1045
 
        return shares
 
507
        return self.syncdaemon_shares.get_shares()
1046
508
 
1047
509
    @dbus.service.method(DBUS_IFACE_SHARES_NAME,
1048
510
                         in_signature='s', out_signature='',
1055
517
 
1056
518
        """
1057
519
        logger.debug('accept_share: %r', share_id)
1058
 
        if str(share_id) in self.vm.shares:
1059
 
            self.vm.accept_share(str(share_id), True)
1060
 
            reply_handler()
1061
 
        else:
1062
 
            error_handler(ValueError("The share with id: %s don't exists" % \
1063
 
                                     str(share_id)))
 
520
        self.syncdaemon_shares.accept_share(share_id, reply_handler,
 
521
                                            error_handler)
 
522
        
1064
523
 
1065
524
    @dbus.service.method(DBUS_IFACE_SHARES_NAME,
1066
525
                         in_signature='s', out_signature='',
1068
527
    def reject_share(self, share_id, reply_handler=None, error_handler=None):
1069
528
        """Reject a share."""
1070
529
        logger.debug('reject_share: %r', share_id)
1071
 
        if str(share_id) in self.vm.shares:
1072
 
            self.vm.accept_share(str(share_id), False)
1073
 
            reply_handler()
1074
 
        else:
1075
 
            error_handler(ValueError("The share with id: %s don't exists" % \
1076
 
                                     str(share_id)))
 
530
        self.syncdaemon_shares.reject_share(share_id, reply_handler,
 
531
                                            error_handler)
1077
532
 
1078
533
    @dbus.service.method(DBUS_IFACE_SHARES_NAME,
1079
534
                         in_signature='s', out_signature='')
1080
535
    def delete_share(self, share_id):
1081
536
        """Delete a Share, both kinds: "to me" and "from me"."""
1082
 
        from ubuntuone.syncdaemon.volume_manager import VolumeDoesNotExist
1083
537
        logger.debug('delete_share: %r', share_id)
1084
538
        try:
1085
 
            try:
1086
 
                self.vm.delete_volume(str(share_id))
1087
 
            except VolumeDoesNotExist:
1088
 
                # isn't a volume! it might be a "share from me (a.k.a shared)"
1089
 
                self.vm.delete_share(str(share_id))
 
539
            self.syncdaemon_shares.delete_share(share_id)
1090
540
        except Exception, e:
1091
541
            logger.exception('Error while deleting share: %r', share_id)
1092
542
            self.ShareDeleteError({'volume_id':share_id}, str(e))
1097
547
    def subscribe(self, share_id):
1098
548
        """Subscribe to the specified share."""
1099
549
        logger.debug('Shares.subscribe: %r', share_id)
1100
 
        d = self.vm.subscribe_share(str(share_id))
1101
 
        msg = 'subscribe_share for id %r failed with %r'
1102
 
        d.addErrback(lambda f: logger.error(msg, share_id, f))
 
550
        self.syncdaemon_shares.subscribe(share_id)
1103
551
 
1104
552
    @dbus.service.method(DBUS_IFACE_SHARES_NAME, in_signature='s')
1105
553
    def unsubscribe(self, share_id):
1106
554
        """Unsubscribe from the specified share."""
1107
555
        logger.debug('Shares.unsubscribe: %r', share_id)
1108
 
        self.vm.unsubscribe_share(str(share_id))
 
556
        self.syncdaemon_shares.unsubscribe(share_id)
1109
557
 
1110
558
    @dbus.service.signal(DBUS_IFACE_SHARES_NAME,
1111
559
                         signature='a{ss}')
1112
560
    def ShareChanged(self, share_dict):
1113
 
        """ A share changed, share_dict contains all the share attributes. """
 
561
        """A share changed, share_dict contains all the share attributes."""
1114
562
 
1115
563
    @dbus.service.signal(DBUS_IFACE_SHARES_NAME,
1116
564
                         signature='a{ss}')
1117
565
    def ShareDeleted(self, share_dict):
1118
 
        """ A share was deleted, share_dict contains all available
1119
 
        share attributes. """
 
566
        """A share was deleted, share_dict contains all available share
 
567
        attributes."""
1120
568
 
1121
569
    @dbus.service.signal(DBUS_IFACE_SHARES_NAME,
1122
570
                         signature='a{ss}s')
1123
571
    def ShareDeleteError(self, share_dict, error):
1124
 
        """ A share was deleted, share_dict contains all available
1125
 
        share attributes. """
 
572
        """A share was deleted, share_dict contains all available
 
573
        share attributes."""
1126
574
 
1127
575
    def emit_share_changed(self, message, share):
1128
 
        """ emits ShareChanged or ShareDeleted signal for the share
 
576
        """Emit ShareChanged or ShareDeleted signal for the share
1129
577
        notification.
1130
578
        """
1131
579
        logger.debug('emit_share_changed: message %r, share %r.',
1132
580
                    message, share)
1133
581
        if message == 'deleted':
1134
 
            self.ShareDeleted(_get_share_dict(share))
 
582
            self.ShareDeleted(get_share_dict(share))
1135
583
        elif message == 'changed':
1136
 
            self.ShareChanged(_get_share_dict(share))
 
584
            self.ShareChanged(get_share_dict(share))
1137
585
 
1138
586
    def emit_share_delete_error(self, share, error):
1139
 
        """Emits ShareDeleteError signal."""
 
587
        """Emit ShareDeleteError signal."""
1140
588
        logger.info('emit_share_delete_error: share %r, error %r.',
1141
589
                    share, error)
1142
 
        self.ShareDeleteError(_get_share_dict(share), error)
 
590
        self.ShareDeleteError(get_share_dict(share), error)
1143
591
 
1144
592
    def emit_free_space(self, share_id, free_bytes):
1145
 
        """ emits ShareChanged when free space changes """
1146
 
        if share_id in self.vm.shares:
1147
 
            share = self.vm.shares[share_id]
1148
 
            share_dict = _get_share_dict(share)
 
593
        """Emit ShareChanged when free space changes """
 
594
        if share_id in self.syncdaemon_shares.shares:
 
595
            share = self.syncdaemon_shares.shares[share_id]
 
596
            share_dict = get_share_dict(share)
1149
597
            share_dict['free_bytes'] = unicode(free_bytes)
1150
598
            self.ShareChanged(share_dict)
1151
599
 
1152
600
    @dbus.service.method(DBUS_IFACE_SHARES_NAME,
1153
601
                         in_signature='ssss', out_signature='')
1154
602
    def create_share(self, path, username, name, access_level):
1155
 
        """ Share a subtree to the user identified by username.
 
603
        """Share a subtree to the user identified by username.
1156
604
 
1157
605
        @param path: that path to share (the root of the subtree)
1158
606
        @param username: the username to offer the share to
1161
609
        """
1162
610
        logger.debug('create share: %r, %r, %r, %r',
1163
611
                     path, username, name, access_level)
1164
 
        path = path.encode("utf8")
1165
 
        username = unicode(username)
1166
 
        name = unicode(name)
1167
 
        access_level = str(access_level)
1168
 
        try:
1169
 
            self.fs_manager.get_by_path(path)
1170
 
        except KeyError:
1171
 
            raise ValueError("path '%r' does not exist" % path)
1172
 
        self.vm.create_share(path, username, name, access_level)
 
612
        self.syncdaemon_shares.create_share(path, username, name, access_level)
1173
613
 
1174
614
    @dbus.service.method(DBUS_IFACE_SHARES_NAME,
1175
615
                         in_signature='sasss', out_signature='')
1184
624
        logger.debug('create shares: %r, %r, %r, %r',
1185
625
                     path, usernames, name, access_level)
1186
626
        for user in usernames:
1187
 
            self.create_share(path, user, name, access_level)
 
627
            self.syncdaemon_shares.create_share(path, user, name,
 
628
                                                access_level)
1188
629
 
1189
630
    @dbus.service.signal(DBUS_IFACE_SHARES_NAME,
1190
631
                         signature='a{ss}')
1191
632
    def ShareCreated(self, share_info):
1192
 
        """ The requested share was succesfully created. """
 
633
        """The requested share was succesfully created."""
1193
634
 
1194
635
    @dbus.service.signal(DBUS_IFACE_SHARES_NAME,
1195
636
                         signature='a{ss}s')
1196
637
    def ShareCreateError(self, share_info, error):
1197
 
        """ An error ocurred while creating the share. """
 
638
        """An error ocurred while creating the share."""
1198
639
 
1199
640
    def emit_share_created(self, share_info):
1200
 
        """ emits ShareCreated signal """
 
641
        """Emit ShareCreated signal """
1201
642
        logger.debug('emit_share_created: share_info %r.', share_info)
1202
643
        self.ShareCreated(share_info)
1203
644
 
1204
645
    def emit_share_create_error(self, share_info, error):
1205
646
        """Emit ShareCreateError signal."""
1206
 
        path = self.fs_manager.get_by_mdid(str(share_info['marker'])).path
1207
 
        share_info.update(dict(path=path))
 
647
        info = self.syncdaemon_shares.get_create_error_share_info(share_info)
1208
648
        logger.info('emit_share_create_error: share_info %r, error %r.',
1209
 
                    share_info, error)
1210
 
        self.ShareCreateError(share_info, error)
 
649
                    info, error)
 
650
        self.ShareCreateError(info, error)
1211
651
 
1212
652
    @dbus.service.method(DBUS_IFACE_SHARES_NAME,
1213
653
                         in_signature='', out_signature='')
1214
654
    def refresh_shares(self):
1215
 
        """ Refresh the share list, requesting it to the server. """
1216
 
        self.vm.refresh_shares()
 
655
        """Refresh the share list, requesting it to the server."""
 
656
        self.syncdaemon_shares.refresh_shares() 
1217
657
 
1218
658
    @dbus.service.method(DBUS_IFACE_SHARES_NAME,
1219
659
                         in_signature='', out_signature='aa{ss}')
1220
660
    def get_shared(self):
1221
 
        """ returns a list of dicts, each dict represents a shared share.
 
661
        """Return a list of dicts, each dict represents a shared share.
1222
662
        A share might not have the path set, as we might be still fetching the
1223
663
        nodes from the server. In this cases the path is ''
1224
664
        """
1225
665
        logger.debug('called get_shared')
1226
 
        shares = []
1227
 
        for share_id, share in self.vm.shared.items():
1228
 
            if share_id == '':
1229
 
                continue
1230
 
            share_dict = _get_share_dict(share)
1231
 
            shares.append(share_dict)
1232
 
        return shares
 
666
        return self.syncdaemon_shares.get_shared()
1233
667
 
1234
668
    @dbus.service.signal(DBUS_IFACE_SHARES_NAME,
1235
669
                         signature='a{ss}')
1251
685
 
1252
686
    def emit_new_share(self, share_id):
1253
687
        """Emits NewShare signal."""
1254
 
        share = self.vm.get_volume(share_id)
 
688
        share = self.syncdaemon_shares.get_volume(share_id)
1255
689
        logger.debug('emit_new_share: share_id %r.', share_id)
1256
 
        self.NewShare(_get_share_dict(share))
 
690
        self.NewShare(get_share_dict(share))
1257
691
 
1258
692
    def emit_share_subscribed(self, share):
1259
693
        """Emit the ShareSubscribed signal"""
1260
 
        share_dict = _get_share_dict(share)
 
694
        share_dict = get_share_dict(share)
1261
695
        self.ShareSubscribed(share_dict)
1262
696
 
1263
697
    @dbus.service.signal(DBUS_IFACE_SHARES_NAME, signature='a{ss}')
1276
710
 
1277
711
    def emit_share_unsubscribed(self, share):
1278
712
        """Emit the ShareUnSubscribed signal"""
1279
 
        share_dict = _get_share_dict(share)
 
713
        share_dict = get_share_dict(share)
1280
714
        self.ShareUnSubscribed(share_dict)
1281
715
 
1282
716
    @dbus.service.signal(DBUS_IFACE_SHARES_NAME, signature='a{ss}')
1295
729
 
1296
730
 
1297
731
class Config(DBusExposedObject):
1298
 
    """ The Syncdaemon config/settings dbus interface. """
 
732
    """The Syncdaemon config/settings dbus interface."""
1299
733
 
1300
734
    def __init__(self, bus_name, dbus_iface):
1301
 
        """ Creates the instance.
 
735
        """Create the instance.
1302
736
 
1303
737
        @param bus: the BusName of this DBusExposedObject.
1304
738
        """
1305
 
        self.dbus_iface = dbus_iface
 
739
        self.syncdaemon_config = SyncdaemonConfig(dbus_iface.main,
 
740
                                                  dbus_iface.action_queue)
1306
741
        self.path = '/config'
1307
742
        DBusExposedObject.__init__(self, bus_name=bus_name,
1308
743
                                   path=self.path)
1317
752
        The values are bytes/second
1318
753
        """
1319
754
        logger.debug("called get_throttling_limits")
1320
 
        try:
1321
 
            aq = self.dbus_iface.action_queue
1322
 
            download = -1
1323
 
            upload = -1
1324
 
            if aq.readLimit is not None:
1325
 
                download = aq.readLimit
1326
 
            if aq.writeLimit is not None:
1327
 
                upload = aq.writeLimit
1328
 
            info = dict(download=download,
1329
 
                        upload=upload)
1330
 
            if reply_handler:
1331
 
                reply_handler(info)
1332
 
            else:
1333
 
                return info
1334
 
            # pylint: disable-msg=W0703
1335
 
        except Exception, e:
1336
 
            if error_handler:
1337
 
                error_handler(e)
1338
 
            else:
1339
 
                raise
 
755
        return self.syncdaemon_config.get_throttling_limits(reply_handler,
 
756
                                                            error_handler)
1340
757
 
1341
758
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1342
759
                         in_signature='ii', out_signature='',
1345
762
                         reply_handler=None, error_handler=None):
1346
763
        """Set the read and write limits. The expected values are bytes/sec."""
1347
764
        logger.debug("called set_throttling_limits")
1348
 
        try:
1349
 
            # modify and save the config file
1350
 
            user_config = config.get_user_config()
1351
 
            user_config.set_throttling_read_limit(download)
1352
 
            user_config.set_throttling_write_limit(upload)
1353
 
            user_config.save()
1354
 
            # modify AQ settings
1355
 
            aq = self.dbus_iface.action_queue
1356
 
            if download == -1:
1357
 
                download = None
1358
 
            if upload == -1:
1359
 
                upload = None
1360
 
            aq.readLimit = download
1361
 
            aq.writeLimit = upload
1362
 
            if reply_handler:
1363
 
                reply_handler()
1364
 
            # pylint: disable-msg=W0703
1365
 
        except Exception, e:
1366
 
            if error_handler:
1367
 
                error_handler(e)
1368
 
            else:
1369
 
                raise
 
765
        self.syncdaemon_config.set_throttling_limits(download, upload,
 
766
                                                     reply_handler,
 
767
                                                     error_handler)
1370
768
 
1371
769
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1372
770
                         in_signature='', out_signature='',
1374
772
    def enable_bandwidth_throttling(self, reply_handler=None,
1375
773
                                    error_handler=None):
1376
774
        """Enable bandwidth throttling."""
1377
 
        try:
1378
 
            self._set_throttling_enabled(True)
1379
 
            if reply_handler:
1380
 
                reply_handler()
1381
 
            # pylint: disable-msg=W0703
1382
 
        except Exception, e:
1383
 
            if error_handler:
1384
 
                error_handler(e)
1385
 
            else:
1386
 
                raise
 
775
        self.syncdaemon_config.enable_bandwidth_throttling(reply_handler,
 
776
                                                           error_handler)
1387
777
 
1388
778
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1389
779
                         in_signature='', out_signature='',
1391
781
    def disable_bandwidth_throttling(self, reply_handler=None,
1392
782
                                     error_handler=None):
1393
783
        """Disable bandwidth throttling."""
1394
 
        try:
1395
 
            self._set_throttling_enabled(False)
1396
 
            if reply_handler:
1397
 
                reply_handler()
1398
 
            # pylint: disable-msg=W0703
1399
 
        except Exception, e:
1400
 
            if error_handler:
1401
 
                error_handler(e)
1402
 
            else:
1403
 
                raise
1404
 
 
1405
 
    def _set_throttling_enabled(self, enabled):
1406
 
        """set throttling enabled value and save the config"""
1407
 
        # modify and save the config file
1408
 
        user_config = config.get_user_config()
1409
 
        user_config.set_throttling(enabled)
1410
 
        user_config.save()
1411
 
        # modify AQ settings
1412
 
        if enabled:
1413
 
            self.dbus_iface.action_queue.enable_throttling()
1414
 
        else:
1415
 
            self.dbus_iface.action_queue.disable_throttling()
 
784
        self.syncdaemon_config.disable_bandwidth_throttling(reply_handler,
 
785
                                                            error_handler)
1416
786
 
1417
787
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1418
788
                         in_signature='', out_signature='b',
1422
792
        """Returns True (actually 1) if bandwidth throttling is enabled and
1423
793
        False (0) otherwise.
1424
794
        """
1425
 
        enabled = self.dbus_iface.action_queue.throttling_enabled
1426
 
        if reply_handler:
1427
 
            reply_handler(enabled)
1428
 
        else:
1429
 
            return enabled
 
795
        return self.syncdaemon_config.bandwidth_throttling_enabled(
 
796
                                                reply_handler, error_handler)
1430
797
 
1431
798
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1432
799
                         in_signature='', out_signature='b')
1433
800
    def udf_autosubscribe_enabled(self):
1434
801
        """Return the udf_autosubscribe config value."""
1435
 
        return config.get_user_config().get_udf_autosubscribe()
 
802
        return self.syncdaemon_config.udf_autosubscribe_enabled()
1436
803
 
1437
804
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1438
805
                         in_signature='', out_signature='')
1439
806
    def enable_udf_autosubscribe(self):
1440
807
        """Enable UDF autosubscribe."""
1441
 
        user_config = config.get_user_config()
1442
 
        user_config.set_udf_autosubscribe(True)
1443
 
        user_config.save()
 
808
        self.syncdaemon_config.enable_udf_autosubscribe()
1444
809
 
1445
810
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1446
811
                         in_signature='', out_signature='')
1447
812
    def disable_udf_autosubscribe(self):
1448
 
        """Enable UDF autosubscribe."""
1449
 
        user_config = config.get_user_config()
1450
 
        user_config.set_udf_autosubscribe(False)
1451
 
        user_config.save()
 
813
        """Disable UDF autosubscribe."""
 
814
        self.syncdaemon_config.disable_udf_autosubscribe()
1452
815
 
1453
816
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1454
817
                         in_signature='', out_signature='b')
1455
818
    def share_autosubscribe_enabled(self):
1456
819
        """Return the share_autosubscribe config value."""
1457
 
        return config.get_user_config().get_share_autosubscribe()
 
820
        return self.syncdaemon_config.share_autosubscribe_enabled()
1458
821
 
1459
822
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1460
823
                         in_signature='', out_signature='')
1461
824
    def enable_share_autosubscribe(self):
1462
 
        """Enable UDF autosubscribe."""
1463
 
        user_config = config.get_user_config()
1464
 
        user_config.set_share_autosubscribe(True)
1465
 
        user_config.save()
 
825
        """Enable share autosubscribe."""
 
826
        self.syncdaemon_config.enable_share_autosubscribe()
1466
827
 
1467
828
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1468
829
                         in_signature='', out_signature='')
1469
830
    def disable_share_autosubscribe(self):
1470
 
        """Enable UDF autosubscribe."""
1471
 
        user_config = config.get_user_config()
1472
 
        user_config.set_share_autosubscribe(False)
1473
 
        user_config.save()
 
831
        """Disable share autosubscribe."""
 
832
        self.syncdaemon_config.disable_share_autosubscribe()
1474
833
 
1475
834
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1476
835
                         in_signature='b', out_signature='')
1477
836
    def set_files_sync_enabled(self, enabled):
1478
837
        """Enable/disable file sync service."""
1479
838
        logger.debug('called set_files_sync_enabled %d', enabled)
1480
 
        user_config = config.get_user_config()
1481
 
        user_config.set_files_sync_enabled(bool(int(enabled)))
1482
 
        user_config.save()
 
839
        self.syncdaemon_config.set_files_sync_enabled(enabled)
1483
840
 
1484
841
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1485
842
                         in_signature='', out_signature='b')
1486
843
    def files_sync_enabled(self):
1487
844
        """Return the files_sync_enabled config value."""
1488
845
        logger.debug('called files_sync_enabled')
1489
 
        return config.get_user_config().get_files_sync_enabled()
 
846
        return self.syncdaemon_config.files_sync_enabled()
1490
847
 
1491
848
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1492
849
                         in_signature='', out_signature='b')
1493
850
    def autoconnect_enabled(self):
1494
851
        """Return the autoconnect config value."""
1495
 
        return config.get_user_config().get_autoconnect()
 
852
        return self.syncdaemon_config.autoconnect_enabled()
1496
853
 
1497
854
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
1498
855
                         in_signature='b', out_signature='')
1499
856
    def set_autoconnect_enabled(self, enabled):
1500
857
        """Enable syncdaemon autoconnect."""
1501
 
        user_config = config.get_user_config()
1502
 
        user_config.set_autoconnect(enabled)
1503
 
        user_config.save()
 
858
        self.syncdaemon_config.set_autoconnect_enabled(enabled)
 
859
 
 
860
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
 
861
                         in_signature='', out_signature='b')
 
862
    def show_all_notifications_enabled(self):
 
863
        """Return the show_all_notifications config value."""
 
864
        return self.syncdaemon_config.show_all_notifications_enabled()
 
865
 
 
866
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
 
867
                         in_signature='', out_signature='')
 
868
    def enable_show_all_notifications(self):
 
869
        """Enable showing all notifications."""
 
870
        self.syncdaemon_config.enable_show_all_notifications()
 
871
 
 
872
    @dbus.service.method(DBUS_IFACE_CONFIG_NAME,
 
873
                         in_signature='', out_signature='')
 
874
    def disable_show_all_notifications(self):
 
875
        """Disable showing all notifications."""
 
876
        self.syncdaemon_config.disable_show_all_notifications()
1504
877
 
1505
878
 
1506
879
class Folders(DBusExposedObject):
1507
880
    """A dbus interface to interact with User Defined Folders"""
1508
881
 
1509
882
    def __init__(self, bus_name, volume_manager, fs_manager):
1510
 
        """ Creates the instance. """
1511
 
        self.vm = volume_manager
1512
 
        self.fs = fs_manager
 
883
        """Create the instance."""
 
884
        self.syncdaemon_folders = SyncdaemonFolders(volume_manager, fs_manager)
1513
885
        self.path = '/folders'
1514
886
        DBusExposedObject.__init__(self, bus_name=bus_name,
1515
887
                                   path=self.path)
1519
891
        """Create a user defined folder in the specified path."""
1520
892
        logger.debug('Folders.create: %r', path)
1521
893
        try:
1522
 
            path = os.path.normpath(path)
1523
 
            self.vm.create_udf(path.encode('utf-8'))
 
894
            self.syncdaemon_folders.create(path)
1524
895
        except Exception, e:
1525
896
            logger.exception('Error while creating udf: %r', path)
1526
897
            self.emit_folder_create_error(path, str(e))
1531
902
        from ubuntuone.syncdaemon.volume_manager import VolumeDoesNotExist
1532
903
        logger.debug('Folders.delete: %r', folder_id)
1533
904
        try:
1534
 
            self.vm.delete_volume(str(folder_id))
 
905
            self.syncdaemon_folders.delete(folder_id)
1535
906
        except VolumeDoesNotExist, e:
1536
907
            self.FolderDeleteError({'volume_id':folder_id}, str(e))
1537
908
        except Exception, e:
1542
913
    def get_folders(self):
1543
914
        """Return the list of folders (a list of dicts)"""
1544
915
        logger.debug('Folders.get_folders')
1545
 
        return [_get_udf_dict(udf) for udf in self.vm.udfs.values()]
 
916
        return self.syncdaemon_folders.get_folders()
1546
917
 
1547
918
    @dbus.service.method(DBUS_IFACE_FOLDERS_NAME,
1548
919
                         in_signature='s', out_signature='')
1549
920
    def subscribe(self, folder_id):
1550
921
        """Subscribe to the specified folder"""
1551
922
        logger.debug('Folders.subscribe: %r', folder_id)
1552
 
        try:
1553
 
            self.vm.subscribe_udf(str(folder_id))
1554
 
        except Exception:
1555
 
            logger.exception('Error while subscribing udf: %r', folder_id)
1556
 
            raise
 
923
        self.syncdaemon_folders.subscribe(folder_id)
1557
924
 
1558
925
    @dbus.service.method(DBUS_IFACE_FOLDERS_NAME,
1559
926
                         in_signature='s', out_signature='')
1560
927
    def unsubscribe(self, folder_id):
1561
928
        """Unsubscribe from the specified folder"""
1562
929
        logger.debug('Folders.unsubscribe: %r', folder_id)
1563
 
        try:
1564
 
            self.vm.unsubscribe_udf(str(folder_id))
1565
 
        except Exception:
1566
 
            logger.exception('Error while unsubscribing udf: %r', folder_id)
1567
 
            raise
 
930
        self.syncdaemon_folders.unsubscribe(folder_id)
1568
931
 
1569
932
    @dbus.service.method(DBUS_IFACE_FOLDERS_NAME,
1570
933
                         in_signature='s', out_signature='a{ss}')
1571
934
    def get_info(self, path):
1572
 
        """Returns a dict containing the folder information."""
 
935
        """Return a dict containing the folder information."""
1573
936
        logger.debug('Folders.get_info: %r', path)
1574
 
        mdobj = self.fs.get_by_path(path.encode('utf-8'))
1575
 
        udf = self.vm.udfs.get(mdobj.share_id, None)
1576
 
        if udf is None:
1577
 
            return dict()
1578
 
        else:
1579
 
            return _get_udf_dict(udf)
 
937
        return self.syncdaemon_folders.get_info(path)
1580
938
 
1581
939
    @dbus.service.method(DBUS_IFACE_FOLDERS_NAME,
1582
940
                         in_signature='', out_signature='')
1583
941
    def refresh_volumes(self):
1584
942
        """Refresh the volumes list, requesting it to the server."""
1585
 
        self.vm.refresh_volumes()
 
943
        self.syncdaemon_folders.refresh_volumes()
1586
944
 
1587
945
    def emit_folder_created(self, folder):
1588
946
        """Emit the FolderCreated signal"""
1589
 
        udf_dict = _get_udf_dict(folder)
 
947
        udf_dict = get_udf_dict(folder)
1590
948
        self.FolderCreated(udf_dict)
1591
949
 
1592
950
    @dbus.service.signal(DBUS_IFACE_FOLDERS_NAME,
1606
964
 
1607
965
    def emit_folder_deleted(self, folder):
1608
966
        """Emit the FolderCreated signal"""
1609
 
        udf_dict = _get_udf_dict(folder)
 
967
        udf_dict = get_udf_dict(folder)
1610
968
        self.FolderDeleted(udf_dict)
1611
969
 
1612
970
    @dbus.service.signal(DBUS_IFACE_FOLDERS_NAME,
1616
974
 
1617
975
    def emit_folder_delete_error(self, folder, error):
1618
976
        """Emit the FolderCreateError signal"""
1619
 
        udf_dict = _get_udf_dict(folder)
 
977
        udf_dict = get_udf_dict(folder)
1620
978
        self.FolderDeleteError(udf_dict, str(error))
1621
979
 
1622
980
    @dbus.service.signal(DBUS_IFACE_FOLDERS_NAME,
1626
984
 
1627
985
    def emit_folder_subscribed(self, folder):
1628
986
        """Emit the FolderSubscribed signal"""
1629
 
        udf_dict = _get_udf_dict(folder)
 
987
        udf_dict = get_udf_dict(folder)
1630
988
        self.FolderSubscribed(udf_dict)
1631
989
 
1632
990
    @dbus.service.signal(DBUS_IFACE_FOLDERS_NAME,
1645
1003
 
1646
1004
    def emit_folder_unsubscribed(self, folder):
1647
1005
        """Emit the FolderUnSubscribed signal"""
1648
 
        udf_dict = _get_udf_dict(folder)
 
1006
        udf_dict = get_udf_dict(folder)
1649
1007
        self.FolderUnSubscribed(udf_dict)
1650
1008
 
1651
1009
    @dbus.service.signal(DBUS_IFACE_FOLDERS_NAME,
1667
1025
    """A DBus interface for handling public files."""
1668
1026
 
1669
1027
    def __init__(self, bus_name, fs_manager, action_queue):
1670
 
        self.fs = fs_manager
1671
 
        self.aq = action_queue
 
1028
        self.syncdaemon_public_files = SyncdaemonPublicFiles(fs_manager,
 
1029
                                                             action_queue)
1672
1030
        self.path = '/publicfiles'
1673
1031
        DBusExposedObject.__init__(self, bus_name=bus_name, path=self.path)
1674
1032
 
1678
1036
        """Change the public access of a file."""
1679
1037
        logger.debug('PublicFiles.change_public_access: %r, %r, %r',
1680
1038
                     share_id, node_id, is_public)
1681
 
        if share_id:
1682
 
            share_id = uuid.UUID(share_id)
1683
 
        else:
1684
 
            share_id = None
1685
 
        node_id = uuid.UUID(node_id)
1686
 
        self.aq.change_public_access(share_id, node_id, is_public)
 
1039
        self.syncdaemon_public_files.change_public_access(share_id, node_id,
 
1040
                                                          is_public)
1687
1041
 
1688
1042
    @dbus.service.method(DBUS_IFACE_PUBLIC_FILES_NAME)
1689
1043
    def get_public_files(self):
1691
1045
 
1692
1046
        The result will be send in a PublicFilesList signal.
1693
1047
        """
1694
 
        self.aq.get_public_files()
 
1048
        self.syncdaemon_public_files.get_public_files()
1695
1049
 
1696
1050
    def emit_public_access_changed(self, share_id, node_id, is_public,
1697
1051
                                   public_url):
1698
1052
        """Emit the PublicAccessChanged signal."""
1699
1053
        share_id = str(share_id) if share_id else ''
1700
1054
        node_id = str(node_id)
1701
 
        try:
1702
 
            relpath = self.fs.get_by_node_id(share_id,
1703
 
                                             node_id).path
1704
 
        except KeyError:
1705
 
            path=''
1706
 
        else:
1707
 
            path=self.fs.get_abspath(share_id, relpath)
 
1055
        path = self.syncdaemon_public_files.get_path(share_id, node_id)
1708
1056
        self.PublicAccessChanged(dict(
1709
1057
                share_id=str(share_id) if share_id else '',
1710
1058
                node_id=str(node_id),
1719
1067
 
1720
1068
    def emit_public_access_change_error(self, share_id, node_id, error):
1721
1069
        """Emit the PublicAccessChangeError signal."""
1722
 
        try:
1723
 
            relpath = self.fs.get_by_node_id(share_id,
1724
 
                                             node_id).path
1725
 
        except KeyError:
1726
 
            path=''
1727
 
        else:
1728
 
            path=self.fs.get_abspath(share_id, relpath)
 
1070
        path = self.syncdaemon_public_files.get_path(share_id, node_id)
1729
1071
        self.PublicAccessChangeError(dict(
1730
1072
                share_id=str(share_id) if share_id else '',
1731
1073
                node_id=str(node_id),
1750
1092
        """Emit the PublicFilesList signal."""
1751
1093
        files = []
1752
1094
        for pf in public_files:
1753
 
            try:
1754
 
                volume_id = str(pf['volume_id'])
1755
 
                node_id = str(pf['node_id'])
1756
 
                public_url = str(pf['public_url'])
1757
 
                relpath = self.fs.get_by_node_id(volume_id,
1758
 
                                                 pf['node_id']).path
1759
 
            except KeyError:
1760
 
                pass
1761
 
            else:
1762
 
                path = self.fs.get_abspath(volume_id, relpath).decode('utf-8')
1763
 
                files.append(dict(volume_id=volume_id, node_id=node_id,
1764
 
                                  public_url=public_url, path=path))
 
1095
            volume_id = str(pf['volume_id'])
 
1096
            node_id = str(pf['node_id'])
 
1097
            public_url = str(pf['public_url'])
 
1098
            path = self.syncdaemon_public_files.get_path(volume_id ,
 
1099
                node_id).decode('utf-8')
 
1100
            files.append(dict(volume_id=volume_id, node_id=node_id,
 
1101
                public_url=public_url, path=path))
1765
1102
        self.PublicFilesList(files)
1766
1103
 
1767
1104
    def emit_public_files_list_error(self, error):
1770
1107
 
1771
1108
 
1772
1109
class DBusInterface(object):
1773
 
    """ Holder of all DBus exposed objects """
 
1110
    """Holder of all DBus exposed objects."""
1774
1111
    test = False
1775
1112
 
1776
1113
    def __init__(self, bus, main, system_bus=None, send_events=False):
1777
 
        """ Create the instance and add the exposed object to the
 
1114
        """Create the instance and add the exposed object to the
1778
1115
        specified bus.
1779
1116
        """
1780
1117
        self.bus = bus
1789
1126
 
1790
1127
        # event listeners
1791
1128
        self.events = Events(self.busName, self.event_queue)
1792
 
        self.event_listener = EventListener(self)
 
1129
        self.event_listener = SyncdaemonEventListener(self)
1793
1130
        if self.send_events:
1794
1131
            self.all_events_sender = AllEventsSender(self)
1795
1132
            self.event_queue.subscribe(self.all_events_sender)
1862
1199
        logger.info('DBusInterface initialized.')
1863
1200
 
1864
1201
    def shutdown(self, with_restart=False):
1865
 
        """ remove the registered object from the bus and unsubscribe from the
 
1202
        """Remove the registered object from the bus and unsubscribe from the
1866
1203
        event queue.
1867
1204
        """
1868
1205
        logger.info('Shuttingdown DBusInterface!')
1905
1242
    _restart_error_handler = _restart_reply_handler
1906
1243
 
1907
1244
    def connection_state_changed(self, state):
1908
 
        """ Push a connection state changed event to the Event Queue. """
 
1245
        """Push a connection state changed event to the Event Queue."""
1909
1246
        event = NM_STATE_EVENTS.get(state, None)
1910
1247
        if event is not None:
1911
1248
            self.event_queue.push(event)
1988
1325
                iface.find_credentials(reply_handler=lambda: None,
1989
1326
                                       error_handler=error_handler)
1990
1327
            else:
1991
 
                iface.register(reply_handler=lambda: None,
 
1328
                iface.register({'window_id': '0'},  # no window ID
 
1329
                               reply_handler=lambda: None,
1992
1330
                               error_handler=error_handler)
1993
1331
        except DBusException, e:
1994
1332
            error_handler(e)
2006
1344
        return d
2007
1345
 
2008
1346
    def disconnect(self):
2009
 
        """ Push the SYS_USER_DISCONNECT event. """
 
1347
        """Push the SYS_USER_DISCONNECT event."""
2010
1348
        self.event_queue.push('SYS_USER_DISCONNECT')
2011
1349
 
2012
1350
    def quit(self):
2013
 
        """ calls Main.quit. """
 
1351
        """Call Main.quit. """
2014
1352
        logger.debug('Calling Main.quit')
2015
1353
        self.main.quit()