def initialize(self):
        """ This is called when a backend is enabled """
        super(Backend, self).initialize()

        if "state" not in self._parameters:
            self._parameters["state"] = "start"

        # Prepare parameters
        jid = self._parameters["username"]
        password = self._parameters["password"]
        server = "pubsub." + jid.split('@', 1)[-1]

        self._xmpp = PubsubClient(jid, password, server)
        self._xmpp.register_callback("failed_auth", self.on_failed_auth)
        self._xmpp.register_callback("connected", self.on_connected)
        self._xmpp.register_callback("disconnected", self.on_disconnected)

        if self._xmpp.connect(reattempt=False):
            self._xmpp.process()
        else:
            Log.error("Can't connect to XMPP")
            if self._parameters["state"] == "start":
                self.on_failed_auth()

        BackendSignals().connect('sharing-changed', self.on_sharing_changed)

        self._xmpp.register_callback("project_tag", self.on_new_remote_project)
        self._xmpp.register_callback("set_task", self.on_remote_set_task)
        self._xmpp.register_callback("rm_task", self.on_remote_rm_task)
    def _get_avatar(self, jid):
        """ Return avatar for jid if it is possible.

        The avatar is cached for the future runs.
        """
        if not os.path.exists(self.AVATARS_DIR):
            os.makedirs(self.AVATARS_DIR)

        # If avatar was cached, return it
        avatars = glob.glob(os.path.join(self.AVATARS_DIR, jid + ".*"))
        if len(avatars) > 0:
            return avatars[0]

        # Download vCard and avatar in it
        vcard = self['xep_0054'].get_vcard(jid)
        img_type = vcard['vcard_temp']['PHOTO']['TYPE']
        photo = vcard['vcard_temp']['PHOTO']['BINVAL']

        # Determine a name for the file
        if not img_type.startswith("image/") or " " in img_type:
            return None
        suffix = img_type[len("image/"):]
        name = os.path.join(self.AVATARS_DIR, "%s.%s" % (jid, suffix))

        Log.info("Saving avatar for '%s'" % jid)
        with open(name, 'wb') as avatar_file:
            avatar_file.write(photo)

        return name
Beispiel #3
0
 def __init__(self):
     """
      Creates a dictionary of the currently available backend modules
     """
     super(BackendFactory, self).__init__()
     if hasattr(self, "backend_modules"):
         # This object has already been constructed
         return
     self.backend_modules = {}
     # Look for backends in the GTG/backends dir
     this_dir = os.path.dirname(__file__)
     backend_files = filter(
         lambda f: f.endswith(".py") and f.startswith(self.BACKEND_PREFIX),
         os.listdir(this_dir))
     # Create module names
     module_names = map(lambda f: f.replace(".py", ""), backend_files)
     #Log.debug("Backends found: " + str(module_names))
     #print "Backends = " + str(module_names)
     # Load backend modules
     for module_name in module_names:
         extended_module_name = "GTG.backends." + module_name
         try:
             __import__(extended_module_name)
         except ImportError, exception:
             # Something is wrong with this backend, skipping
             Log.warning("Backend %s could not be loaded: %s" %
                         (module_name, str(exception)))
             continue
         except Exception, exception:
             # Other exception log as errors
             Log.error("Malformated backend %s: %s" %
                       (module_name, str(exception)))
             continue
Beispiel #4
0
    def restore_backend_from_xml(self, dic):
        '''
        Function restoring a backend from its xml description.
        dic should be a dictionary containing at least the key
            - "module", with the module name
            - "xmlobject", with its xml description.
        Every other key is passed as-is to the backend, as parameter.

        Returns the backend instance, or None is something goes wrong
        '''
        if not "module" in dic or not "xmlobject" in dic:
            Log.debug("Malformed backend configuration found! %s" %
                      dic)
        module = self.get_backend(dic["module"])
        if module is None:
            Log.debug("could not load module for backend %s" %
                      dic["module"])
            return None
        # we pop the xml object, as it will be redundant when the parameters
        # are set directly in the dict
        xp = dic.pop("xmlobject")
        # Building the dictionary
        parameters_specs = module.Backend.get_static_parameters()
        dic["pid"] = str(xp.getAttribute("pid"))
        for param_name, param_dic in parameters_specs.iteritems():
            if xp.hasAttribute(param_name):
                # we need to convert the parameter to the right format.
                # we fetch the format from the static_parameters
                param_type = param_dic[GenericBackend.PARAM_TYPE]
                param_value = GenericBackend.cast_param_type_from_string(
                    xp.getAttribute(param_name), param_type)
                dic[param_name] = param_value
        # We put the backend itself in the dict
        dic["backend"] = module.Backend(dic)
        return dic["backend"]
    def on_remote_set_task(self, task_id, raw_xml):
        """ Task was set on server """
        if self._parameters["state"] != "online":
            return

        if task_id in self._changed_locally:
            self._changed_locally.remove(task_id)
            return

        Log.info("PubSub --set--> GTG: [%s]" % task_id)

        # Parse XML string into <task> node
        xmldoc = xml.dom.minidom.parseString(raw_xml)
        task_xml = xmldoc.getElementsByTagName("task")[0]

        self._changed_remotely.add(task_id)
        task = self.datastore.get_task(task_id)
        if task:
            # Already exists
            task = task_from_xml(task, task_xml)
        else:
            # New task
            task = self.datastore.task_factory(task_id)
            task = task_from_xml(task, task_xml)
            self.datastore.push_task(task)
Beispiel #6
0
    def _show_panel(self, panel_name):
        '''
        Helper function to switch between panels.

        @param panel_name: the name of the wanted panel. Choose between
                        "configuration" or "add"
        '''
        if panel_name == "configuration":
            panel_to_remove = self.add_panel
            panel_to_add = self.config_panel
            side_is_enabled = True
        elif panel_name == "add":
            panel_to_remove = self.config_panel
            panel_to_add = self.add_panel
            side_is_enabled = False
        else:
            Log.error("panel name unknown")
            return
        # Central pane
        # NOTE: self.central_pane is the Gtk.Container in which we load panels
        if panel_to_remove in self.central_pane:
            self.central_pane.remove(panel_to_remove)
        if not panel_to_add in self.central_pane:
            self.central_pane.add(panel_to_add)
        self.central_pane.show_all()
        # Side treeview
        # disabled if we're adding a new backend
        try:
            # when this is called upon initialization of this class, the
            # backends_tv object has not been created yet.
            self.add_button.set_sensitive(side_is_enabled)
            self.remove_button.set_sensitive(side_is_enabled)
            self.backends_tv.set_sensitive(side_is_enabled)
        except AttributeError:
            pass
    def set_task(self, task):
        """ Propagate a change in local tasks into server """
        if self._parameters["state"] != "online":
            return

        sync_tags = self._xmpp.get_synchronized_tags()
        tags = task.get_tags_name()
        tag_overlap = set(sync_tags) & set(tags)
        if not tag_overlap:
            return

        if task.get_id() in self._changed_remotely:
            self._changed_remotely.remove(task.get_id())
            return

        Log.info("GTG --set--> PubSub: [%s] '%s'" %
                 (task.get_id(), task.get_title()))

        doc = xml.dom.minidom.parseString("<task></task>")
        task_id = task.get_id()
        task_xml = task_to_xml(doc, task).toxml()
        tags = task.get_tags_name()

        self._xmpp.set_task(task_id, tags, task_xml)
        self._sync_tasks.add(task_id)
        self._changed_locally.add(task_id)
    def save_state(self):
        """ The last function before shutting this backend down.

        Disconnect XMPP and store picked_file """
        Log.info("Quitting backend")
        self._xmpp.disconnect()
        Log.info("Backend is shut down")
def openxmlfile(zefile,root ):
    tmpfile = zefile+'__'
#    print "opening %s file" %zefile
    try:
        if os.path.exists(zefile):
            f = open(zefile, "r")
        elif os.path.exists(tmpfile):
            Log.debug("Something happened to the tags file. Using backup")
            os.rename(tmpfile, zefile)
            f = open(zefile, "r")
        else:
            # Creating empty file
            doc,xmlproject = emptydoc(root)
            newfile = savexml(zefile, doc) # use our function to save file
            if not newfile:
                sys.exit(1)
            return openxmlfile(zefile, root) # recursive call
        stringed = f.read()
        stringed = cleanString(stringed,tab,enter)
        doc = xml.dom.minidom.parseString(stringed)
#        doc = xml.dom.minidom.parse(f)
#        print "cleaning %s" %zefile
        cleanDoc(doc,tab,enter)
        xmlproject = doc.getElementsByTagName(root)[0]
        f.close()
        return doc,xmlproject
    except IOError, msg:
        print msg
        sys.exit(1)
Beispiel #10
0
    def restore_backend_from_xml(self, dic):
        '''
        Function restoring a backend from its xml description.
        dic should be a dictionary containing at least the key
            - "module", with the module name
            - "xmlobject", with its xml description.
        Every other key is passed as-is to the backend, as parameter.

        Returns the backend instance, or None is something goes wrong
        '''
        if not "module" in dic or not "xmlobject" in dic:
            Log.debug("Malformed backend configuration found! %s" % dic)
        module = self.get_backend(dic["module"])
        if module is None:
            Log.debug("could not load module for backend %s" % dic["module"])
            return None
        # we pop the xml object, as it will be redundant when the parameters
        # are set directly in the dict
        xp = dic.pop("xmlobject")
        # Building the dictionary
        parameters_specs = module.Backend.get_static_parameters()
        dic["pid"] = str(xp.getAttribute("pid"))
        for param_name, param_dic in parameters_specs.iteritems():
            if xp.hasAttribute(param_name):
                # we need to convert the parameter to the right format.
                # we fetch the format from the static_parameters
                param_type = param_dic[GenericBackend.PARAM_TYPE]
                param_value = GenericBackend.cast_param_type_from_string(
                    xp.getAttribute(param_name), param_type)
                dic[param_name] = param_value
        # We put the backend itself in the dict
        dic["backend"] = module.Backend(dic)
        return dic["backend"]
    def on_connected(self):
        """ Get the initial set of the tasks from the XMPP """
        if self._parameters["state"] != "onine":
            self._parameters["state"] = "online"

        # Ensure all teams
        tag_tree = self.datastore.get_tagstore().get_main_view()
        for tag_id in tag_tree.get_all_nodes():
            tag = self.datastore.get_tag(tag_id)
            team = tag.get_people_shared_with()
            if len(team) > 0:
                self._xmpp.ensure_team(tag_id, team)

        # Fetch initial tasks
        for task_id, tag, raw_xml in self._xmpp.get_tasks():
            # Parse the raw_xml by DOM
            doc = xml.dom.minidom.parseString(raw_xml)
            task_xml = doc.getElementsByTagName("task")[0]

            # Create a new task or return the existing one with the same id
            task = self.datastore.task_factory(task_id)
            task = task_from_xml(task, task_xml)
            task.add_tag(tag)
            self.datastore.push_task(task)

            self._sync_tasks.add(task_id)
            Log.info("(init) PubSub --set--> GTG: [%s] '%s'" %
                     (task_id, task.get_title()))
    def _get_avatar(self, jid):
        """ Return avatar for jid if it is possible.

        The avatar is cached for the future runs.
        """
        if not os.path.exists(self.AVATARS_DIR):
            os.makedirs(self.AVATARS_DIR)

        # If avatar was cached, return it
        avatars = glob.glob(os.path.join(self.AVATARS_DIR, jid + ".*"))
        if len(avatars) > 0:
            return avatars[0]

        # Download vCard and avatar in it
        vcard = self['xep_0054'].get_vcard(jid)
        img_type = vcard['vcard_temp']['PHOTO']['TYPE']
        photo = vcard['vcard_temp']['PHOTO']['BINVAL']

        # Determine a name for the file
        if not img_type.startswith("image/") or " " in img_type:
            return None
        suffix = img_type[len("image/"):]
        name = os.path.join(self.AVATARS_DIR, "%s.%s" % (jid, suffix))

        Log.info("Saving avatar for '%s'" % jid)
        with open(name, 'wb') as avatar_file:
            avatar_file.write(photo)

        return name
Beispiel #13
0
    def new_search_tag(self, name, query, attributes={}):
        """
        Create a new search tag

        @returns GTG.core.tag.Tag: the new search tag/None for a invalid query
        """
        try:
            parameters = parse_search_query(query)
        except InvalidQuery as e:
            Log.warning("Problem with parsing query '%s' (skipping): %s" %
                        (query, e.message))
            return None

        # Create own copy of attributes and add special attributes label, query
        init_attr = dict(attributes)
        init_attr["label"] = name
        init_attr["query"] = query

        tag = Tag(name, req=self.requester, attributes=init_attr)
        self._add_new_tag(name,
                          tag,
                          search_filter,
                          parameters,
                          parent_id=SEARCH_TAG)
        self.save_tagtree()
        return tag
Beispiel #14
0
    def get(self, option):
        """ Get option from configuration.

        If the option is not specified in the configuration or is of invalid
        type, return default value. If there is no default value,
        None is returned
        """
        default_value = self._defaults.get(option)
        if default_value is None:
            Log.warning(
                'No default value for %s in %s', option, self._section_name)

        get_function = self._type_function(default_value)

        try:
            value = get_function(option)
        except ValueError as e:
            value = None
            Log.warning(
                'Invalid configuration value "%s" for %s in %s: %s',
                self._section.get(option), option, self._section_name, e)

        if value is None and default_value is None:
            raise ValueError(
                'No valid configuration value or default value was '
                'found for %s in %s'.format(option, self._section_name))
        elif value is None:
            return default_value
        else:
            return value
    def on_remote_set_task(self, task_id, raw_xml):
        """ Task was set on server """
        if self._parameters["state"] != "online":
            return

        if task_id in self._changed_locally:
            self._changed_locally.remove(task_id)
            return

        Log.info("PubSub --set--> GTG: [%s]" % task_id)

        # Parse XML string into <task> node
        xmldoc = xml.dom.minidom.parseString(raw_xml)
        task_xml = xmldoc.getElementsByTagName("task")[0]

        self._changed_remotely.add(task_id)
        task = self.datastore.get_task(task_id)
        if task:
            # Already exists
            task = task_from_xml(task, task_xml)
        else:
            # New task
            task = self.datastore.task_factory(task_id)
            task = task_from_xml(task, task_xml)
            self.datastore.push_task(task)
 def __init__(self):
     """
      Creates a dictionary of the currently available backend modules
     """
     super(BackendFactory, self).__init__()
     if hasattr(self, "backend_modules"):
         #This object has already been constructed
         return
     self.backend_modules = {}
     #Look for backends in the GTG/backends dir
     this_dir = os.path.dirname(__file__)
     backend_files = filter(lambda f: f.endswith(".py") and     \
            f[ : len(self.BACKEND_PREFIX)] == self.BACKEND_PREFIX , \
            os.listdir(this_dir))
     #Create module names
     module_names = map(lambda f: f.replace(".py",""), backend_files)
     Log.debug("Backends found: " + str(module_names))
     #Load backend modules
     for module_name in module_names:
         extended_module_name = "GTG.backends." + module_name
         try:
             __import__(extended_module_name)
         except ImportError, exception:
             #Something is wrong with this backend, skipping
             Log.debug("Backend %s could not be loaded: %s" % \
                       (module_name, str(exception)))
             continue
         self.backend_modules[module_name] = \
                 sys.modules[extended_module_name]
    def set_task(self, task):
        """ Propagate a change in local tasks into server """
        if self._parameters["state"] != "online":
            return

        sync_tags = self._xmpp.get_synchronized_tags()
        tags = task.get_tags_name()
        tag_overlap = set(sync_tags) & set(tags)
        if not tag_overlap:
            return

        if task.get_id() in self._changed_remotely:
            self._changed_remotely.remove(task.get_id())
            return

        Log.info("GTG --set--> PubSub: [%s] '%s'" % (task.get_id(),
                task.get_title()))

        doc = xml.dom.minidom.parseString("<task></task>")
        task_id = task.get_id()
        task_xml = task_to_xml(doc, task).toxml()
        tags = task.get_tags_name()

        self._xmpp.set_task(task_id, tags, task_xml)
        self._sync_tasks.add(task_id)
        self._changed_locally.add(task_id)
    def save_state(self):
        """ The last function before shutting this backend down.

        Disconnect XMPP and store picked_file """
        Log.info("Quitting backend")
        self._xmpp.disconnect()
        Log.info("Backend is shut down")
    def on_connected(self):
        """ Get the initial set of the tasks from the XMPP """
        if self._parameters["state"] != "onine":
            self._parameters["state"] = "online"

        # Ensure all teams
        tag_tree = self.datastore.get_tagstore().get_main_view()
        for tag_id in tag_tree.get_all_nodes():
            tag = self.datastore.get_tag(tag_id)
            team = tag.get_people_shared_with()
            if len(team) > 0:
                self._xmpp.ensure_team(tag_id, team)

        # Fetch initial tasks
        for task_id, tag, raw_xml in self._xmpp.get_tasks():
            # Parse the raw_xml by DOM
            doc = xml.dom.minidom.parseString(raw_xml)
            task_xml = doc.getElementsByTagName("task")[0]

            # Create a new task or return the existing one with the same id
            task = self.datastore.task_factory(task_id)
            task = task_from_xml(task, task_xml)
            task.add_tag(tag)
            self.datastore.push_task(task)

            self._sync_tasks.add(task_id)
            Log.info("(init) PubSub --set--> GTG: [%s] '%s'" %
                (task_id, task.get_title()))
    def initialize(self):
        """ This is called when a backend is enabled """
        super(Backend, self).initialize()

        if "state" not in self._parameters:
            self._parameters["state"] = "start"

        # Prepare parameters
        jid = self._parameters["username"]
        password = self._parameters["password"]
        server = "pubsub." + jid.split('@', 1)[-1]

        self._xmpp = PubsubClient(jid, password, server)
        self._xmpp.register_callback("failed_auth", self.on_failed_auth)
        self._xmpp.register_callback("connected", self.on_connected)
        self._xmpp.register_callback("disconnected", self.on_disconnected)

        if self._xmpp.connect(reattempt=False):
            self._xmpp.process()
        else:
            Log.error("Can't connect to XMPP")
            if self._parameters["state"] == "start":
                self.on_failed_auth()

        BackendSignals().connect('sharing-changed', self.on_sharing_changed)

        self._xmpp.register_callback("project_tag", self.on_new_remote_project)
        self._xmpp.register_callback("set_task", self.on_remote_set_task)
        self._xmpp.register_callback("rm_task", self.on_remote_rm_task)
Beispiel #21
0
def openxmlfile(zefile, root):
    """ Open an XML file in a robust way

    If file could not be opened, try:
        - file__
        - file.bak.0
        - file.bak.1
        - .... until BACKUP_NBR

    If file doesn't exist, create a new file """

    tmpfile = zefile + '__'
    try:
        if os.path.exists(zefile):
            return _try_openxmlfile(zefile, root)
        elif os.path.exists(tmpfile):
            Log.warning("Something happened to %s. Using backup" % zefile)
            os.rename(tmpfile, zefile)
            return _try_openxmlfile(zefile, root)
        else:
            # Creating empty file
            doc, xmlproject = emptydoc(root)
            newfile = savexml(zefile, doc)
            if not newfile:
                Log.error("Could not create a new file %s" % zefile)
                sys.exit(1)
            return _try_openxmlfile(zefile, root)

    except IOError, msg:
        print msg
        sys.exit(1)
Beispiel #22
0
def openxmlfile(zefile, root):
    """ Open an XML file in a robust way

    If file could not be opened, try:
        - file__
        - file.bak.0
        - file.bak.1
        - .... until BACKUP_NBR

    If file doesn't exist, create a new file """

    tmpfile = zefile + '__'
    try:
        if os.path.exists(zefile):
            return _try_openxmlfile(zefile, root)
        elif os.path.exists(tmpfile):
            Log.warning("Something happened to %s. Using backup" % zefile)
            os.rename(tmpfile, zefile)
            return _try_openxmlfile(zefile, root)
        else:
            # Creating empty file
            doc, xmlproject = emptydoc(root)
            newfile = savexml(zefile, doc)
            if not newfile:
                Log.error("Could not create a new file %s" % zefile)
                sys.exit(1)
            return _try_openxmlfile(zefile, root)

    except IOError, msg:
        print msg
        sys.exit(1)
Beispiel #23
0
    def _show_panel(self, panel_name):
        '''
        Helper function to switch between panels.

        @param panel_name: the name of the wanted panel. Choose between
                        "configuration" or "add"
        '''
        if panel_name == "configuration":
            panel_to_remove = self.add_panel
            panel_to_add = self.config_panel
            side_is_enabled = True
        elif panel_name == "add":
            panel_to_remove = self.config_panel
            panel_to_add = self.add_panel
            side_is_enabled = False
        else:
            Log.error("panel name unknown")
            return
        # Central pane
        # NOTE: self.central_pane is the Gtk.Container in which we load panels
        if panel_to_remove in self.central_pane:
            self.central_pane.remove(panel_to_remove)
        if panel_to_add not in self.central_pane:
            self.central_pane.add(panel_to_add)
        self.central_pane.show_all()
        # Side treeview
        # disabled if we're adding a new backend
        try:
            # when this is called upon initialization of this class, the
            # backends_tv object has not been created yet.
            self.add_button.set_sensitive(side_is_enabled)
            self.remove_button.set_sensitive(side_is_enabled)
            self.backends_tv.set_sensitive(side_is_enabled)
        except AttributeError:
            pass
Beispiel #24
0
    def set_task(self, task):
        """
        See GenericBackend for an explanation of this function.
        """
        self.cancellation_point()
        is_syncable = self._gtg_task_is_syncable_per_attached_tags(task)
        tid = task.get_id()
        with self.datastore.get_backend_mutex():
            with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy:
                has_task = self.datastore.has_task
                has_note = tomboy.NoteExists
                can_sync = is_syncable
                with self.DbusWatchdog(self):
                    action, note = self.sync_engine.analyze_local_id(tid, has_task, has_note, can_sync)
                Log.debug("processing gtg (%s, %d)" % (action, is_syncable))

                if action == SyncEngine.ADD:
                    # GTG allows multiple tasks with the same name,
                    # Tomboy doesn't. we need to handle the renaming
                    # manually
                    title = task.get_title()
                    duplicate_counter = 1
                    with self.DbusWatchdog(self):
                        note = tomboy.CreateNamedNote(title)
                        while note == "":
                            duplicate_counter += 1
                            note = tomboy.CreateNamedNote(title + "(%d)" % duplicate_counter)
                    if duplicate_counter != 1:
                        # if we needed to rename, we have to rename also
                        # the gtg task
                        task.set_title(title + " (%d)" % duplicate_counter)

                    self._populate_note(note, task)
                    self.record_relationship(
                        local_id=tid,
                        remote_id=note,
                        meme=SyncMeme(task.get_modified(), self.get_modified_for_note(note), "GTG"),
                    )

                elif action == SyncEngine.UPDATE:
                    meme = self.sync_engine.get_meme_from_local_id(task.get_id())
                    modified_for = self.get_modified_for_note(note)
                    newest = meme.which_is_newest(task.get_modified(), modified_for)
                    if newest == "local":
                        self._populate_note(note, task)
                        meme.set_local_last_modified(task.get_modified())
                        meme.set_remote_last_modified(self.get_modified_for_note(note))
                        self.save_state()

                elif action == SyncEngine.REMOVE:
                    self.datastore.request_task_deletion(tid)
                    try:
                        self.sync_engine.break_relationship(local_id=tid)
                        self.save_state()
                    except KeyError:
                        pass

                elif action == SyncEngine.LOST_SYNCABILITY:
                    self._exec_lost_syncability(tid, note)
Beispiel #25
0
    def _process_rtm_task(self, rtm_task_id):
        '''
        Takes a rtm task id and carries out the necessary operations to
        refresh the sync state
        '''
        self.cancellation_point()
        if not self.rtm_proxy.is_authenticated():
            return
        rtm_task = self.rtm_proxy.get_rtm_tasks_dict()[rtm_task_id]
        is_syncable = self._rtm_task_is_syncable_per_attached_tags(rtm_task)
        action, tid = self.sync_engine.analyze_remote_id(
            rtm_task_id, self.datastore.has_task, self.rtm_proxy.has_rtm_task,
            is_syncable)
        Log.debug("GTG<-RTM set task (%s, %s)" % (action, is_syncable))

        if action is None:
            return

        if action == SyncEngine.ADD:
            if rtm_task.get_status() != Task.STA_ACTIVE:
                # OPTIMIZATION:
                # we don't sync tasks that have already been closed before we
                # even saw them
                return
            tid = str(uuid.uuid4())
            task = self.datastore.task_factory(tid)
            self._populate_task(task, rtm_task)
            meme = SyncMeme(task.get_modified(), rtm_task.get_modified(),
                            "RTM")
            self.sync_engine.record_relationship(local_id=tid,
                                                 remote_id=rtm_task_id,
                                                 meme=meme)
            self.datastore.push_task(task)

        elif action == SyncEngine.UPDATE:
            task = self.datastore.get_task(tid)
            with self.datastore.get_backend_mutex():
                meme = self.sync_engine.get_meme_from_remote_id(rtm_task_id)
                newest = meme.which_is_newest(task.get_modified(),
                                              rtm_task.get_modified())
                if newest == "remote":
                    self._populate_task(task, rtm_task)
                    meme.set_remote_last_modified(rtm_task.get_modified())
                    meme.set_local_last_modified(task.get_modified())
                else:
                    # we skip saving the state
                    return

        elif action == SyncEngine.REMOVE:
            try:
                rtm_task.delete()
                self.sync_engine.break_relationship(remote_id=rtm_task_id)
            except KeyError:
                pass

        elif action == SyncEngine.LOST_SYNCABILITY:
            self._exec_lost_syncability(tid, rtm_task)

        self.save_state()
    def on_failed_auth(self):
        """ Provided credencials are not valid.

        Disable this instance and show error to user """
        Log.error('Failed to authenticate')
        BackendSignals().backend_failed(self.get_id(),
                        BackendSignals.ERRNO_AUTHENTICATION)
        self.quit(disable=True)
Beispiel #27
0
 def get_configuration(self):
     try:
         return datetime.time(int(self.config.get('hour')),
                              int(self.config.get('min')))
     except(ValueError):
         Log.error("Invalid time values: %s:%s", self.config.get('hour'),
                   self.config.get('min'))
         return datetime.time(0, 0)
Beispiel #28
0
 def _when_taking_too_long(self):
     """
     Function that is executed when the Dbus connection seems to be
     hanging. It disables the backend and signals the error to the user.
     """
     Log.error("Dbus connection is taking too long for the Tomboy/Gnote" "backend!")
     BackendSignals().backend_failed(self.backend.get_id(), BackendSignals.ERRNO_DBUS)
     self.backend.quit(disable=True)
Beispiel #29
0
 def on_task_modified(self, task_id, path):
     """ Stop task if it is tracked and it is Done/Dismissed """
     Log.debug('Hamster: task modified %s', task_id)
     task = self.plugin_api.get_requester().get_task(task_id)
     if not task:
         return
     if task.get_status() in (Task.STA_DISMISSED, Task.STA_DONE):
         self.stop_task(task_id)
Beispiel #30
0
 def on_task_modified(self, task_id, path):
     """ Stop task if it is tracked and it is Done/Dismissed """
     Log.debug('Hamster: task modified %s', task_id)
     task = self.plugin_api.get_requester().get_task(task_id)
     if not task:
         return
     if task.get_status() in (Task.STA_DISMISSED, Task.STA_DONE):
         self.stop_task(task_id)
Beispiel #31
0
 def get_configuration(self):
     try:
         return datetime.time(int(self.config.get('hour')),
                              int(self.config.get('min')))
     except (ValueError):
         Log.error("Invalid time values: %s:%s", self.config.get('hour'),
                   self.config.get('min'))
         return datetime.time(0, 0)
    def on_failed_auth(self):
        """ Provided credencials are not valid.

        Disable this instance and show error to user """
        Log.error('Failed to authenticate')
        BackendSignals().backend_failed(self.get_id(),
                                        BackendSignals.ERRNO_AUTHENTICATION)
        self.quit(disable=True)
 def get_tasks(self):
     """ Return list of all available tasks """
     Log.info("Looking for available tasks")
     for node in self._nodes:
         project_tag = self._nodes[node]
         result_items = self['xep_0060'].get_items(self._pubsub, node,
                 max_items=self.MAX_ITEMS, block=True)
         items = result_items['pubsub']['items']['substanzas']
         for item in items:
             yield item['id'], project_tag, tostring(item['payload'])
 def adding_tag(tname,tag):
     if not self.__tagstore.has_node(tname):
         p = {'tag':tname,'transparent':True}
         self.__tasks.add_filter(tname,self.treefactory.tag_filter,parameters=p)
         self.__tagstore.add_node(tag)
         tag.set_save_callback(self.save)
         self.added_tag.pop(tname)
         Log.debug("********* tag added %s *******" % tname)
     else:
         print "Warning: Trying to add tag %s multiple times" %tname
Beispiel #35
0
 def get_backend(self, backend_name):
     '''
     Returns the backend module for the backend matching
     backend_name. Else, returns none
     '''
     if backend_name in self.backend_modules:
         return self.backend_modules[backend_name]
     else:
         Log.debug("Trying to load backend %s, but failed!" % backend_name)
         return None
Beispiel #36
0
 def open_browser(self):
     if not self.browser:
         self.browser = TaskBrowser(self.req, self)
     # notify user if backup was used
     backend_dic = self.req.get_all_backends()
     for backend in backend_dic:
         if backend.get_name() == "backend_localfile" and \
                 backend.used_backup():
             backend.notify_user_about_backup()
     Log.debug("Browser is open")
Beispiel #37
0
 def _when_taking_too_long(self):
     '''
     Function that is executed when the Dbus connection seems to be
     hanging. It disables the backend and signals the error to the user.
     '''
     Log.error("Dbus connection is taking too long for the Tomboy/Gnote"
               "backend!")
     BackendSignals().backend_failed(self.backend.get_id(),
                                     BackendSignals.ERRNO_DBUS)
     self.backend.quit(disable=True)
Beispiel #38
0
 def get_backend(self, backend_name):
     '''
     Returns the backend module for the backend matching
     backend_name. Else, returns none
     '''
     if backend_name in self.backend_modules:
         return self.backend_modules[backend_name]
     else:
         Log.debug("Trying to load backend %s, but failed!" % backend_name)
         return None
Beispiel #39
0
 def open_browser(self):
     if not self.browser:
         self.browser = TaskBrowser(self.req, self)
     # notify user if backup was used
     backend_dic = self.req.get_all_backends()
     for backend in backend_dic:
         if backend.get_name() == "backend_localfile" and \
                 backend.used_backup():
             backend.notify_user_about_backup()
     Log.debug("Browser is open")
Beispiel #40
0
    def set_task(self, task):
        '''
        See GenericBackend for an explanation of this function.
        '''
        tid = task.get_id()
        is_syncable = self._gtg_task_is_syncable_per_attached_tags(task)
        action, evo_task_id = self.sync_engine.analyze_local_id(
            tid,
            self.datastore.has_task,
            self._evo_has_task,
            is_syncable)
        Log.debug('GTG->Evo set task (%s, %s)' % (action, is_syncable))

        if action is None:
            return

        if action == SyncEngine.ADD:
            evo_task = evolution.ecal.ECalComponent(
                ical=evolution.ecal.CAL_COMPONENT_TODO)
            with self.datastore.get_backend_mutex():
                self._evolution_tasks.add_object(evo_task)
                self._populate_evo_task(task, evo_task)
                meme = SyncMeme(task.get_modified(),
                                self._evo_get_modified(evo_task),
                                "GTG")
                self.sync_engine.record_relationship(
                    local_id=tid, remote_id=evo_task.get_uid(),
                    meme=meme)

        elif action == SyncEngine.UPDATE:
            with self.datastore.get_backend_mutex():
                evo_task = self._evo_get_task(evo_task_id)
                meme = self.sync_engine.get_meme_from_local_id(task.get_id())
                newest = meme.which_is_newest(task.get_modified(),
                                              self._evo_get_modified(evo_task))
                if newest == "local":
                    self._populate_evo_task(task, evo_task)
                    meme.set_remote_last_modified(
                        self._evo_get_modified(evo_task))
                    meme.set_local_last_modified(task.get_modified())
                else:
                    # we skip saving the state
                    return

        elif action == SyncEngine.REMOVE:
            self.datastore.request_task_deletion(tid)
            try:
                self.sync_engine.break_relationship(local_id=tid)
            except KeyError:
                pass

        elif action == SyncEngine.LOST_SYNCABILITY:
            evo_task = self._evo_get_task(evo_task_id)
            self._exec_lost_syncability(tid, evo_task)
        self.save_state()
    def set_task(self, task):
        '''
        See GenericBackend for an explanation of this function.
        '''
        tid = task.get_id()
        is_syncable = self._gtg_task_is_syncable_per_attached_tags(task)
        action, evo_task_id = self.sync_engine.analyze_local_id(
            tid,
            self.datastore.has_task,
            self._evo_has_task,
            is_syncable)
        Log.debug('GTG->Evo set task (%s, %s)' % (action, is_syncable))

        if action is None:
            return

        if action == SyncEngine.ADD:
            evo_task = evolution.ecal.ECalComponent(
                ical=evolution.ecal.CAL_COMPONENT_TODO)
            with self.datastore.get_backend_mutex():
                self._evolution_tasks.add_object(evo_task)
                self._populate_evo_task(task, evo_task)
                meme = SyncMeme(task.get_modified(),
                                self._evo_get_modified(evo_task),
                                "GTG")
                self.sync_engine.record_relationship(
                    local_id=tid, remote_id=evo_task.get_uid(),
                    meme=meme)

        elif action == SyncEngine.UPDATE:
            with self.datastore.get_backend_mutex():
                evo_task = self._evo_get_task(evo_task_id)
                meme = self.sync_engine.get_meme_from_local_id(task.get_id())
                newest = meme.which_is_newest(task.get_modified(),
                                              self._evo_get_modified(evo_task))
                if newest == "local":
                    self._populate_evo_task(task, evo_task)
                    meme.set_remote_last_modified(
                        self._evo_get_modified(evo_task))
                    meme.set_local_last_modified(task.get_modified())
                else:
                    # we skip saving the state
                    return

        elif action == SyncEngine.REMOVE:
            self.datastore.request_task_deletion(tid)
            try:
                self.sync_engine.break_relationship(local_id=tid)
            except KeyError:
                pass

        elif action == SyncEngine.LOST_SYNCABILITY:
            evo_task = self._evo_get_task(evo_task_id)
            self._exec_lost_syncability(tid, evo_task)
        self.save_state()
Beispiel #42
0
    def _process_tomboy_note(self, note):
        '''
        Given a tomboy note, finds out if it must be synced to a GTG note and,
        if so, it carries out the synchronization (by creating or updating a
        GTG task, or deleting itself if the related task has been deleted)

        @param note: a Tomboy note id
        '''
        with self.datastore.get_backend_mutex():
            self.cancellation_point()
            is_syncable = self._tomboy_note_is_syncable(note)
            has_task = self.datastore.has_task
            note_exists = self._tomboy_note_exists
            with self.DbusWatchdog(self):
                action, tid = self.sync_engine.analyze_remote_id(note,
                                                                 has_task,
                                                                 note_exists,
                                                                 is_syncable)
            Log.debug("processing tomboy (%s, %s)" % (action, is_syncable))

            if action == SyncEngine.ADD:
                tid = str(uuid.uuid4())
                task = self.datastore.task_factory(tid)
                self._populate_task(task, note)
                modified_for = self.get_modified_for_note(note)
                self.record_relationship(local_id=tid,
                                         remote_id=note,
                                         meme=SyncMeme(task.get_modified(),
                                                       modified_for,
                                                       self.get_id()))
                self.datastore.push_task(task)

            elif action == SyncEngine.UPDATE:
                task = self.datastore.get_task(tid)
                meme = self.sync_engine.get_meme_from_remote_id(note)
                newest = meme.which_is_newest(task.get_modified(),
                                              self.get_modified_for_note(note))
                if newest == "remote":
                    self._populate_task(task, note)
                    meme.set_local_last_modified(task.get_modified())
                    meme.set_remote_last_modified(
                        self.get_modified_for_note(note))
                    self.save_state()

            elif action == SyncEngine.REMOVE:
                with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy:
                    with self.DbusWatchdog(self):
                        tomboy.DeleteNote(note)
                    try:
                        self.sync_engine.break_relationship(remote_id=note)
                    except KeyError:
                        pass

            elif action == SyncEngine.LOST_SYNCABILITY:
                self._exec_lost_syncability(tid, note)
Beispiel #43
0
    def _process_tomboy_note(self, note):
        '''
        Given a tomboy note, finds out if it must be synced to a GTG note and,
        if so, it carries out the synchronization (by creating or updating a
        GTG task, or deleting itself if the related task has been deleted)

        @param note: a Tomboy note id
        '''
        with self.datastore.get_backend_mutex():
            self.cancellation_point()
            is_syncable = self._tomboy_note_is_syncable(note)
            has_task = self.datastore.has_task
            note_exists = self._tomboy_note_exists
            with self.DbusWatchdog(self):
                action, tid = self.sync_engine.analyze_remote_id(note,
                                                                 has_task,
                                                                 note_exists,
                                                                 is_syncable)
            Log.debug("processing tomboy (%s, %s)" % (action, is_syncable))

            if action == SyncEngine.ADD:
                tid = str(uuid.uuid4())
                task = self.datastore.task_factory(tid)
                self._populate_task(task, note)
                modified_for = self.get_modified_for_note(note)
                self.record_relationship(local_id=tid,
                                         remote_id=note,
                                         meme=SyncMeme(task.get_modified(),
                                                       modified_for,
                                                       self.get_id()))
                self.datastore.push_task(task)

            elif action == SyncEngine.UPDATE:
                task = self.datastore.get_task(tid)
                meme = self.sync_engine.get_meme_from_remote_id(note)
                newest = meme.which_is_newest(task.get_modified(),
                                              self.get_modified_for_note(note))
                if newest == "remote":
                    self._populate_task(task, note)
                    meme.set_local_last_modified(task.get_modified())
                    meme.set_remote_last_modified(
                        self.get_modified_for_note(note))
                    self.save_state()

            elif action == SyncEngine.REMOVE:
                with self.TomboyConnection(self, *self.BUS_ADDRESS) as tomboy:
                    with self.DbusWatchdog(self):
                        tomboy.DeleteNote(note)
                    try:
                        self.sync_engine.break_relationship(remote_id=note)
                    except KeyError:
                        pass

            elif action == SyncEngine.LOST_SYNCABILITY:
                self._exec_lost_syncability(tid, note)
Beispiel #44
0
    def delete_task(self, tid, recursive=True):
        """Delete the task 'tid' and, by default, delete recursively
        all the childrens.

        Note: this modifies the datastore.

        @param tid: The id of the task to be deleted.
        """
        # send the signal before actually deleting the task !
        Log.debug("deleting task %s" % tid)
        return self.__basetree.del_node(tid, recursive=recursive)
Beispiel #45
0
 def _login(self):
     '''
     Tries to establish a connection to rtm with a token got from the
     authentication process
     '''
     try:
         self.rtm = createRTM(self.PUBLIC_KEY, self.PRIVATE_KEY, self.token)
         self.timeline = self.rtm.timelines.create().timeline
         return True
     except (RTMError, RTMAPIError), e:
         Log.error("RTM ERROR" + str(e))
Beispiel #46
0
    def delete_task(self, tid, recursive=True):
        """Delete the task 'tid' and, by default, delete recursively
        all the childrens.

        Note: this modifies the datastore.

        @param tid: The id of the task to be deleted.
        """
        # send the signal before actually deleting the task !
        Log.debug("deleting task %s" % tid)
        return self.__basetree.del_node(tid, recursive=recursive)
 def _login(self):
     '''
     Tries to establish a connection to rtm with a token got from the
     authentication process
     '''
     try:
         self.rtm = createRTM(self.PUBLIC_KEY, self.PRIVATE_KEY, self.token)
         self.timeline = self.rtm.timelines.create().timeline
         return True
     except (RTMError, RTMAPIError), e:
         Log.error("RTM ERROR" + str(e))
Beispiel #48
0
    def new_search_tag(self, name, query, attributes={}):
        """
        Create a new search tag

        @returns GTG.core.tag.Tag: the new search tag/None for a invalid query
        """
        try:
            parameters = parse_search_query(query)
        except InvalidQuery, e:
            Log.warning("Problem with parsing query '%s' (skipping): %s" %
                        (query, e.message))
            return None
Beispiel #49
0
    def remove_widget_from_taskeditor(self, widg_id):
        """Remove a widget from the bottom of the task editor dialog

        @param widget: The Gtk.Widget that is going to be removed
        """
        if self.is_editor() and widg_id:
            try:
                wi = self.__builder.get_object("vbox4")
                if wi and widg_id in self.taskwidget_widg:
                    wi.remove(self.taskwidget_widg.pop(widg_id))
            except Exception as e:
                Log.debug("Error removing the toolbar item in the TaskEditor:" "%s" % e)
    def on_new_remote_project(self, tag_id, team_jids):
        """ New project was added on server """
        if self._parameters["state"] != "online":
            return
        team = [unicode(member) for member in team_jids]
        Log.info("Pubsub --new project--> GTG: %s, teammates: %s" %
                 (tag_id, team))

        tag = self.datastore.get_tag(tag_id)
        if tag is None:
            tag = self.datastore.new_tag(tag_id)
        tag.set_people_shared_with(team)
 def remove_task(self, task_id):
     """ After removing local task remove tasks from the server """
     if self._parameters["state"] != "online":
         return
     if task_id in self._sync_tasks:
         Log.info("GTG --del--> PubSub: [%s]" % task_id)
         self._xmpp.delete_task(task_id)
         self._sync_tasks.remove(task_id)
         if task_id in self._changed_locally:
             self._changed_locally.remove(task_id)
         if task_id in self._changed_remotely:
             self._changed_remotely.remove(task_id)
Beispiel #52
0
 def new_relationship(self,par,chi):
     if self.thread_protection:
         t = threading.current_thread()
         if t != self.thread:
             raise Exception('! could not new_relationship from thread %s' %t)
     if self.tree:
         return self.tree.new_relationship(par,chi)
     else:
         self.pending_relationship.append([par,chi])
         #it's pending, we return False
         Log.debug("** There's still no tree, relationship is pending")
         return False
Beispiel #53
0
    def new_search_tag(self, name, query, attributes={}):
        """
        Create a new search tag

        @returns GTG.core.tag.Tag: the new search tag/None for a invalid query
        """
        try:
            parameters = parse_search_query(query)
        except InvalidQuery, e:
            Log.warning("Problem with parsing query '%s' (skipping): %s" %
                       (query, e.message))
            return None
    def on_new_remote_project(self, tag_id, team_jids):
        """ New project was added on server """
        if self._parameters["state"] != "online":
            return
        team = [unicode(member) for member in team_jids]
        Log.info("Pubsub --new project--> GTG: %s, teammates: %s" % (tag_id,
                team))

        tag = self.datastore.get_tag(tag_id)
        if tag is None:
            tag = self.datastore.new_tag(tag_id)
        tag.set_people_shared_with(team)
 def get_tasks(self):
     """ Return list of all available tasks """
     Log.info("Looking for available tasks")
     for node in self._nodes:
         project_tag = self._nodes[node]
         result_items = self['xep_0060'].get_items(self._pubsub,
                                                   node,
                                                   max_items=self.MAX_ITEMS,
                                                   block=True)
         items = result_items['pubsub']['items']['substanzas']
         for item in items:
             yield item['id'], project_tag, tostring(item['payload'])
 def remove_task(self, task_id):
     """ After removing local task remove tasks from the server """
     if self._parameters["state"] != "online":
         return
     if task_id in self._sync_tasks:
         Log.info("GTG --del--> PubSub: [%s]" % task_id)
         self._xmpp.delete_task(task_id)
         self._sync_tasks.remove(task_id)
         if task_id in self._changed_locally:
             self._changed_locally.remove(task_id)
         if task_id in self._changed_remotely:
             self._changed_remotely.remove(task_id)
    def _process_evo_task(self, evo_task_id):
        '''
        Takes an evolution task id and carries out the necessary operations to
        refresh the sync state
        '''
        self.cancellation_point()
        evo_task = self._evo_get_task(evo_task_id)
        is_syncable = self._evo_task_is_syncable(evo_task)
        action, tid = self.sync_engine.analyze_remote_id(
            evo_task_id,
            self.datastore.has_task,
            self._evo_has_task,
            is_syncable)
        Log.debug('GTG<-Evo set task (%s, %s)' % (action, is_syncable))

        if action == SyncEngine.ADD:
            with self.datastore.get_backend_mutex():
                tid = str(uuid.uuid4())
                task = self.datastore.task_factory(tid)
                self._populate_task(task, evo_task)
                meme = SyncMeme(task.get_modified(),
                                self._evo_get_modified(evo_task),
                                "GTG")
                self.sync_engine.record_relationship(local_id=tid,
                                                     remote_id=evo_task_id,
                                                     meme=meme)
                self.datastore.push_task(task)

        elif action == SyncEngine.UPDATE:
            with self.datastore.get_backend_mutex():
                task = self.datastore.get_task(tid)
                meme = self.sync_engine.get_meme_from_remote_id(evo_task_id)
                newest = meme.which_is_newest(task.get_modified(),
                                              self._evo_get_modified(evo_task))
                if newest == "remote":
                    self._populate_task(task, evo_task)
                    meme.set_remote_last_modified(
                        self._evo_get_modified(evo_task))
                    meme.set_local_last_modified(task.get_modified())

        elif action == SyncEngine.REMOVE:
            return
            try:
                evo_task = self._evo_get_task(evo_task_id)
                self._delete_evolution_task(evo_task)
                self.sync_engine.break_relationship(remote_id=evo_task)
            except KeyError:
                pass

        elif action == SyncEngine.LOST_SYNCABILITY:
            self._exec_lost_syncability(tid, evo_task)
        self.save_state()
Beispiel #58
0
    def remove_widget_from_taskeditor(self, widg_id):
        """Remove a widget from the bottom of the task editor dialog

        @param widget: The gtk.Widget that is going to be removed
        """
        if self.is_editor() and widg_id:
            try:
                wi = self.__builder.get_object('vbox4')
                if wi and widg_id in self.taskwidget_widg:
                    wi.remove(self.taskwidget_widg.pop(widg_id))
            except Exception, e:
                Log.debug("Error removing the toolbar item in the TaskEditor:"
                          "%s" % e)
Beispiel #59
0
    def __init__(self, req):
        GObject.GObject.__init__(self)
        self.req = req
        self.config_obj = self.req.get_global_config()
        self.browser_config = self.config_obj.get_subconfig("browser")
        self.plugins_config = self.config_obj.get_subconfig("plugins")
        self.task_config = self.config_obj.get_taskconfig()

        # Editors
        self.opened_task = {}  # This is the list of tasks that are already
        # opened in an editor of course it's empty
        # right now

        self.browser = None
        self.__start_browser_hidden = False
        self.gtk_terminate = False  # if true, the gtk main is not started

        # if true, closing the last window doesn't quit GTG
        # (GTG lives somewhere else without GUI, e.g. notification area)
        self.daemon_mode = False

        # Shared clipboard
        self.clipboard = clipboard.TaskClipboard(self.req)

        # Initialize Timer
        self.config = self.req.get_config('browser')
        self.timer = Timer(self.config)

        # Browser (still hidden)
        self.browser = TaskBrowser(self.req, self)

        self.__init_plugin_engine()

        if not self.__start_browser_hidden:
            self.show_browser()

        # Deletion UI
        self.delete_dialog = None

        # Preferences and Backends windows
        # Initialize  dialogs
        self.preferences = PreferencesDialog(self.req, self)
        self.plugins = PluginsDialog(self.config_obj)
        self.edit_backends_dialog = None

        # Tag Editor
        self.tag_editor_dialog = None

        # DBus
        DBusTaskWrapper(self.req, self)
        Log.debug("Manager initialization finished")