Esempio n. 1
0
def add_workspace_to_persistent_json(owner, name, url, path):
    d = utils.get_persistent_data()
    workspaces = d['workspaces']
    if owner not in workspaces:
        workspaces[owner] = {}
    workspaces[owner][name] = {'url': url, 'path': path}
    utils.update_persistent_data(d)
Esempio n. 2
0
def add_workspace_to_persistent_json(owner, name, url, path):
    d = utils.get_persistent_data()
    workspaces = d['workspaces']
    if owner not in workspaces:
        workspaces[owner] = {}
    workspaces[owner][name] = {'url': url, 'path': path}
    utils.update_persistent_data(d)
 def find_workspace(workspace_url):
     r = api.get_workspace_by_url(workspace_url)
     if r.code < 400:
         return r
     try:
         result = utils.parse_url(workspace_url)
         d = utils.get_persistent_data()
         del d['workspaces'][result['owner']][result['name']]
         utils.update_persistent_data(d)
     except Exception as e:
         msg.debug(str_e(e))
Esempio n. 4
0
 def find_workspace(workspace_url):
     r = api.get_workspace_by_url(workspace_url)
     if r.code < 400:
         return r
     try:
         result = utils.parse_url(workspace_url)
         d = utils.get_persistent_data()
         del d['workspaces'][result['owner']][result['name']]
         utils.update_persistent_data(d)
     except Exception as e:
         msg.debug(str_e(e))
Esempio n. 5
0
def update_recent_workspaces(workspace):
    d = utils.get_persistent_data()
    recent_workspaces = d.get('recent_workspaces', [])
    recent_workspaces.insert(0, workspace)
    recent_workspaces = recent_workspaces[:100]
    seen = set()
    new = []
    for r in recent_workspaces:
        string = json.dumps(r)
        if string not in seen:
            new.append(r)
            seen.add(string)
    d['recent_workspaces'] = new
    utils.update_persistent_data(d)
Esempio n. 6
0
def update_recent_workspaces(workspace):
    d = utils.get_persistent_data()
    recent_workspaces = d.get('recent_workspaces', [])
    recent_workspaces.insert(0, workspace)
    recent_workspaces = recent_workspaces[:100]
    seen = set()
    new = []
    for r in recent_workspaces:
        string = json.dumps(r)
        if string not in seen:
            new.append(r)
            seen.add(string)
    d['recent_workspaces'] = new
    utils.update_persistent_data(d)
 def find_workspace(workspace_url):
     r = api.get_workspace_by_url(workspace_url)
     if r.code < 400:
         on_room_info_waterfall.add(ignore.create_flooignore, dir_to_share)
         on_room_info_waterfall.add(lambda: G.AGENT.upload(dir_to_share, on_room_info_msg))
         return r
     try:
         result = utils.parse_url(workspace_url)
         d = utils.get_persistent_data()
         del d['workspaces'][result['owner']][result['name']]
         utils.update_persistent_data(d)
     except Exception as e:
         msg.debug(unicode(e))
     return
Esempio n. 8
0
    def create_or_link_account(self, context, host, force, cb):
        if host != "floobits.com":
            self.link_account(context, host, cb)
            return
        disable_account_creation = utils.get_persistent_data().get(
            'disable_account_creation')
        if disable_account_creation and not force:
            print(
                'We could not automatically create or link your floobits account. Please go to floobits.com and sign up to use this plugin.'
            )
            return

        if not G.EXPERT_MODE:
            editor.message_dialog(
                'Thank you for installing the Floobits plugin!\n\nLet\'s set up your editor to work with Floobits.'
            )

        choices = [
            'Sign in to Floobits', 'Automatically create a Floobits account',
            'Cancel (see https://floobits.com/help/floorc)'
        ]

        (
            choice, index
        ) = yield self.user_select, context, 'You need an account to use Floobits! Do you want to:', choices, None

        if index == -1 or index == 2:
            d = utils.get_persistent_data()
            if not d.get('disable_account_creation'):
                d['disable_account_creation'] = True
                utils.update_persistent_data(d)
                # TODO: this instruction is only useful for Sublime Text
                editor.message_dialog(
                    '''You can set up a Floobits account at any time under:\n\nTools -> Floobits -> Set up'''
                )
            cb(None)
            return

        agent = None
        if index == 0:
            agent = credentials.RequestCredentialsHandler()
        else:
            agent = account.CreateAccountHandler()

        agent.once('end', cb)

        try:
            reactor.reactor.connect(agent, host, G.DEFAULT_PORT, True)
        except Exception as e:
            print(str_e(e))
Esempio n. 9
0
    def create_or_link_account(self, context, host, force, cb):
        if host != "floobits.com":
            self.link_account(context, host, cb)
            return
        disable_account_creation = utils.get_persistent_data().get("disable_account_creation")
        if disable_account_creation and not force:
            print(
                "We could not automatically create or link your floobits account. Please go to floobits.com and sign up to use this plugin."
            )
            return

        if not G.EXPERT_MODE:
            editor.message_dialog(
                "Thank you for installing the Floobits plugin!\n\nLet's set up your editor to work with Floobits."
            )

        choices = ["Sign in to Floobits", "Create a Floobits account", "Cancel (see https://floobits.com/help/floorc)"]

        (choice, index) = (
            yield self.user_select,
            context,
            "You need an account to use Floobits! Do you want to:",
            choices,
            None,
        )

        if index == -1 or index == 2:
            d = utils.get_persistent_data()
            if not d.get("disable_account_creation"):
                d["disable_account_creation"] = True
                utils.update_persistent_data(d)
                # TODO: this instruction is only useful for Sublime Text
                editor.message_dialog(
                    """You can set up a Floobits account at any time under\n\nTools -> Floobits -> Set up"""
                )
            cb(None)
            return

        agent = None
        if index == 0:
            agent = credentials.RequestCredentialsHandler()
        else:
            agent = account.CreateAccountHandler()

        agent.once("end", cb)

        try:
            reactor.reactor.connect(agent, host, G.DEFAULT_PORT, True)
        except Exception as e:
            print(str_e(e))
Esempio n. 10
0
    def prejoin_workspace(self, workspace_url, dir_to_share, api_args):
        try:
            result = utils.parse_url(workspace_url)
        except Exception as e:
            msg.error(str_e(e))
            return False

        host = result.get('host')
        if not api.get_basic_auth(host):
            raise ValueError(
                'No auth credentials for %s. Please add a username and secret for %s in your ~/.floorc.json'
                % (host, host))

        try:
            w = api.get_workspace_by_url(workspace_url)
        except Exception as e:
            editor.error_message('Error opening url %s: %s' %
                                 (workspace_url, str_e(e)))
            return False

        if w.code >= 400:
            try:
                d = utils.get_persistent_data()
                try:
                    del d['workspaces'][result['owner']][result['name']]
                except Exception:
                    pass
                try:
                    del d['recent_workspaces'][workspace_url]
                except Exception:
                    pass
                utils.update_persistent_data(d)
            except Exception as e:
                msg.debug(str_e(e))
            return False

        msg.debug('workspace: ', json.dumps(w.body))
        anon_perms = w.body.get('perms', {}).get('AnonymousUser', [])
        msg.debug('api args: ', api_args)
        new_anon_perms = api_args.get('perms', {}).get('AnonymousUser', [])
        # TODO: prompt/alert user if going from private to public
        if set(anon_perms) != set(new_anon_perms):
            msg.debug(str(anon_perms), str(new_anon_perms))
            w.body['perms']['AnonymousUser'] = new_anon_perms
            response = api.update_workspace(workspace_url, w.body)
            msg.debug(str(response.body))
        utils.add_workspace_to_persistent_json(w.body['owner'], w.body['name'],
                                               workspace_url, dir_to_share)
        return result
Esempio n. 11
0
def migrate_symlinks():
    data = {}
    old_path = os.path.join(G.COLAB_DIR, 'persistent.json')
    if not os.path.exists(old_path):
        return
    old_data = utils.get_persistent_data(old_path)
    data['workspaces'] = get_legacy_projects()
    data['recent_workspaces'] = old_data.get('recent_workspaces')
    utils.update_persistent_data(data)
    try:
        os.unlink(old_path)
        os.unlink(os.path.join(G.COLAB_DIR, 'msgs.floobits.log'))
    except Exception:
        pass
    print('migrated')
Esempio n. 12
0
def migrate_symlinks():
    data = {}
    old_path = os.path.join(G.COLAB_DIR, 'persistent.json')
    if not os.path.exists(old_path):
        return
    old_data = utils.get_persistent_data(old_path)
    data['workspaces'] = get_legacy_projects()
    data['recent_workspaces'] = old_data.get('recent_workspaces')
    utils.update_persistent_data(data)
    try:
        os.unlink(old_path)
        os.unlink(os.path.join(G.COLAB_DIR, 'msgs.floobits.log'))
    except Exception:
        pass
    print('migrated')
Esempio n. 13
0
    def prejoin_workspace(self, workspace_url, dir_to_share, api_args):
        try:
            result = utils.parse_url(workspace_url)
        except Exception as e:
            msg.error(str_e(e))
            return False

        host = result.get("host")
        if not api.get_basic_auth(host):
            raise ValueError(
                "No auth credentials for %s. Please add a username and secret for %s in your ~/.floorc.json"
                % (host, host)
            )

        try:
            w = api.get_workspace_by_url(workspace_url)
        except Exception as e:
            editor.error_message("Error opening url %s: %s" % (workspace_url, str_e(e)))
            return False

        if w.code >= 400:
            try:
                d = utils.get_persistent_data()
                try:
                    del d["workspaces"][result["owner"]][result["name"]]
                except Exception:
                    pass
                try:
                    del d["recent_workspaces"][workspace_url]
                except Exception:
                    pass
                utils.update_persistent_data(d)
            except Exception as e:
                msg.debug(str_e(e))
            return False

        msg.debug("workspace: ", json.dumps(w.body))
        anon_perms = w.body.get("perms", {}).get("AnonymousUser", [])
        msg.debug("api args: ", api_args)
        new_anon_perms = api_args.get("perms", {}).get("AnonymousUser", [])
        # TODO: prompt/alert user if going from private to public
        if set(anon_perms) != set(new_anon_perms):
            msg.debug(str(anon_perms), str(new_anon_perms))
            w.body["perms"]["AnonymousUser"] = new_anon_perms
            response = api.update_workspace(workspace_url, w.body)
            msg.debug(str(response.body))
        utils.add_workspace_to_persistent_json(w.body["owner"], w.body["name"], workspace_url, dir_to_share)
        return result
Esempio n. 14
0
 def find_workspace(workspace_url):
     try:
         api.get_workspace_by_url(workspace_url)
     except HTTPError:
         try:
             result = utils.parse_url(workspace_url)
             d = utils.get_persistent_data()
             del d['workspaces'][result['owner']][result['name']]
             utils.update_persistent_data(d)
         except Exception as e:
             msg.debug(unicode(e))
         return False
     on_room_info_waterfall.add(on_room_info_msg)
     on_room_info_waterfall.add(ignore.create_flooignore, dir_to_share)
     on_room_info_waterfall.add(Listener.create_buf, dir_to_share)
     return True
Esempio n. 15
0
 def find_workspace(workspace_url):
     try:
         api.get_workspace_by_url(workspace_url)
     except HTTPError:
         try:
             result = utils.parse_url(workspace_url)
             d = utils.get_persistent_data()
             del d['workspaces'][result['owner']][result['name']]
             utils.update_persistent_data(d)
         except Exception as e:
             msg.debug(unicode(e))
         return False
     on_room_info_waterfall.add(on_room_info_msg)
     on_room_info_waterfall.add(ignore.create_flooignore, dir_to_share)
     on_room_info_waterfall.add(Listener.create_buf, dir_to_share)
     return True
 def cb(index):
     if index == 0:
         token = binascii.b2a_hex(uuid.uuid4().bytes).decode('utf-8')
         agent = RequestCredentialsHandler(token)
     elif index == 1:
         agent = CreateAccountHandler()
     else:
         d = utils.get_persistent_data()
         if d.get('disable_account_creation'):
             return
         d['disable_account_creation'] = True
         utils.update_persistent_data(d)
         sublime.message_dialog('''You can set up a Floobits account at any time under\n\nTools -> Floobits -> Setup''')
     try:
         reactor.connect(agent, G.DEFAULT_HOST, G.DEFAULT_PORT, True)
     except Exception as e:
         print(str_e(e))
Esempio n. 17
0
 def cb(index):
     if index == 0:
         token = binascii.b2a_hex(uuid.uuid4().bytes).decode('utf-8')
         agent = RequestCredentialsHandler(token)
     elif index == 1:
         agent = CreateAccountHandler()
     else:
         d = utils.get_persistent_data()
         if d.get('disable_account_creation'):
             return
         d['disable_account_creation'] = True
         utils.update_persistent_data(d)
         sublime.message_dialog(
             '''You can set up a Floobits account at any time under\n\nTools -> Floobits -> Setup'''
         )
     try:
         reactor.connect(agent, G.DEFAULT_HOST, G.DEFAULT_PORT, True)
     except Exception as e:
         print(str_e(e))
Esempio n. 18
0
 def find_workspace(workspace_url):
     if ssl is False:
         # No ssl module (broken Sublime Text). Just behave as if the workspace exists.
         return True
     try:
         api.get_workspace_by_url(workspace_url)
     except HTTPError:
         try:
             result = utils.parse_url(workspace_url)
             d = utils.get_persistent_data()
             del d['workspaces'][result['owner']][result['name']]
             utils.update_persistent_data(d)
         except Exception as e:
             msg.debug(unicode(e))
         return False
     on_room_info_waterfall.add(on_room_info_msg)
     on_room_info_waterfall.add(ignore.create_flooignore, dir_to_share)
     on_room_info_waterfall.add(Listener.create_buf, dir_to_share)
     return True
    def _on_room_info(self, data):
        self.reset()
        G.JOINED_WORKSPACE = True
        self.workspace_info = data
        G.PERMS = data['perms']

        if 'patch' not in data['perms']:
            msg.log('No patch permission. Setting buffers to read-only')
            should_send = yield self.ok_cancel_dialog, '''You don't have permission to edit this workspace. All files will be read-only.
Do you want to request edit permission?'''
            if should_send:
                self.send({'name': 'request_perms', 'perms': ['edit_room']})

        floo_json = {
            'url': utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'), floo_json)

        changed_bufs = []
        missing_bufs = []
        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            buf_path = utils.get_full_path(buf['path'])
            new_dir = os.path.dirname(buf_path)
            utils.mkdir(new_dir)
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id

            view = self.get_view(buf_id)
            if view and not view.is_loading() and buf['encoding'] == 'utf8':
                view_text = view.get_text()
                view_md5 = hashlib.md5(view_text.encode('utf-8')).hexdigest()
                if view_md5 == buf['md5']:
                    msg.debug('md5 sum matches view. not getting buffer %s' % buf['path'])
                    buf['buf'] = view_text
                    G.VIEW_TO_HASH[view.native_id] = view_md5
                elif self.should_get_bufs:
                    changed_bufs.append(buf_id)
            else:
                try:
                    buf_fd = open(buf_path, 'rb')
                    buf_buf = buf_fd.read()
                    md5 = hashlib.md5(buf_buf).hexdigest()
                    if md5 == buf['md5']:
                        msg.debug('md5 sum matches. not getting buffer %s' % buf['path'])
                        if buf['encoding'] == 'utf8':
                            buf_buf = buf_buf.decode('utf-8')
                        buf['buf'] = buf_buf
                    elif self.should_get_bufs:
                        changed_bufs.append(buf_id)
                except Exception as e:
                    msg.debug('Error calculating md5:', e)
                    missing_bufs.append(buf_id)

        if changed_bufs and self.should_get_bufs:
            if len(changed_bufs) > 4:
                prompt = '%s local files are different from the workspace. Overwrite your local files?' % len(changed_bufs)
            else:
                prompt = 'Overwrite the following local files?\n'
                for buf_id in changed_bufs:
                    prompt += '\n%s' % self.bufs[buf_id]['path']

            stomp_local = yield self.ok_cancel_dialog, prompt
            for buf_id in changed_bufs:
                if stomp_local:
                    self.get_buf(buf_id)
                    self.save_on_get_bufs.add(buf_id)
                else:
                    buf = self.bufs[buf_id]
                    # TODO: this is inefficient. we just read the file 20 lines ago
                    self.upload(utils.get_full_path(buf['path']))

        for buf_id in missing_bufs:
            self.get_buf(buf_id)

        success_msg = 'Successfully joined workspace %s/%s' % (self.owner, self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace, self.workspace_url, G.PROJECT_PATH)
        self.emit("room_info")
Esempio n. 20
0
    def _on_room_info(self, data):
        self.reset()
        self.joined_workspace = True
        self.workspace_info = data
        G.PERMS = data['perms']

        if 'patch' not in data['perms']:
            no_perms_msg = '''You don't have permission to edit this workspace. All files will be read-only.'''
            msg.log('No patch permission. Setting buffers to read-only')
            if 'request_perm' in data['perms']:
                should_send = yield self.ok_cancel_dialog, no_perms_msg + '\nDo you want to request edit permission?'
                if should_send:
                    self.send({'name': 'request_perms', 'perms': ['edit_room']})
            else:
                editor.error_message(no_perms_msg)

        floo_json = {
            'url': utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'), floo_json)

        changed_bufs = []
        missing_bufs = []
        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            buf_path = utils.get_full_path(buf['path'])
            new_dir = os.path.dirname(buf_path)
            utils.mkdir(new_dir)
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id

            view = self.get_view(buf_id)
            if view and not view.is_loading() and buf['encoding'] == 'utf8':
                view_text = view.get_text()
                view_md5 = hashlib.md5(view_text.encode('utf-8')).hexdigest()
                buf['buf'] = view_text
                buf['view'] = view
                G.VIEW_TO_HASH[view.native_id] = view_md5
                if view_md5 == buf['md5']:
                    msg.debug('md5 sum matches view. not getting buffer %s' % buf['path'])
                else:
                    changed_bufs.append(buf_id)
                    buf['md5'] = view_md5
            else:
                try:
                    if buf['encoding'] == "utf8":
                        if io:
                            buf_fd = io.open(buf_path, 'Urt', encoding='utf8')
                            buf_buf = buf_fd.read()
                        else:
                            buf_fd = open(buf_path, 'rb')
                            buf_buf = buf_fd.read().decode('utf-8').replace('\r\n', '\n')
                        md5 = hashlib.md5(buf_buf.encode('utf-8')).hexdigest()
                    else:
                        buf_fd = open(buf_path, 'rb')
                        buf_buf = buf_fd.read()
                        md5 = hashlib.md5(buf_buf).hexdigest()
                    buf_fd.close()
                    buf['buf'] = buf_buf
                    if md5 == buf['md5']:
                        msg.debug('md5 sum matches. not getting buffer %s' % buf['path'])
                    else:
                        msg.debug('md5 differs. possibly getting buffer later %s' % buf['path'])
                        changed_bufs.append(buf_id)
                        buf['md5'] = md5
                except Exception as e:
                    msg.debug('Error calculating md5 for %s, %s' % (buf['path'], e))
                    missing_bufs.append(buf_id)

        stomp_local = self.should_get_bufs
        if stomp_local and (changed_bufs or missing_bufs):
            changed = [self.bufs[buf_id] for buf_id in changed_bufs]
            missing = [self.bufs[buf_id] for buf_id in missing_bufs]
            choice = yield self.stomp_prompt, changed, missing
            if choice not in [0, 1]:
                self.stop()
                return
            stomp_local = bool(choice)

        for buf_id in changed_bufs:
            buf = self.bufs[buf_id]
            if stomp_local:
                self.get_buf(buf_id, buf.get('view'))
                self.save_on_get_bufs.add(buf_id)
            else:
                self._upload(utils.get_full_path(buf['path']), buf['buf'])

        for buf_id in missing_bufs:
            buf = self.bufs[buf_id]
            if stomp_local:
                self.get_buf(buf_id, buf.get('view'))
                self.save_on_get_bufs.add(buf_id)
            else:
                self.send({
                    'name': 'delete_buf',
                    'id': buf['id'],
                })

        success_msg = 'Successfully joined workspace %s/%s' % (self.owner, self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace, self.workspace_url, G.PROJECT_PATH)
        self.emit("room_info")
Esempio n. 21
0
    def _on_room_info(self, data):
        self.reset()
        G.JOINED_WORKSPACE = True
        self.workspace_info = data
        G.PERMS = data['perms']

        if 'patch' not in data['perms']:
            msg.log('No patch permission. Setting buffers to read-only')
            should_send = yield self.ok_cancel_dialog, 'You don\'t have permission to edit this workspace. All files will be read-only.\n\nDo you want to request edit permission?'
            if should_send:
                self.send({'name': 'request_perms', 'perms': ['edit_room']})

        floo_json = {
            'url': utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'), floo_json)

        changed_bufs = []
        missing_bufs = []
        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            buf_path = utils.get_full_path(buf['path'])
            new_dir = os.path.dirname(buf_path)
            utils.mkdir(new_dir)
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id

            view = self.get_view(buf_id)
            if view and not view.is_loading() and buf['encoding'] == 'utf8':
                view_text = view.get_text()
                view_md5 = hashlib.md5(view_text.encode('utf-8')).hexdigest()
                if view_md5 == buf['md5']:
                    msg.debug('md5 sum matches view. not getting buffer %s' % buf['path'])
                    buf['buf'] = view_text
                    G.VIEW_TO_HASH[view.native_id] = view_md5
                elif self.should_get_bufs:
                    changed_bufs.append(buf_id)
            else:
                try:
                    buf_fd = open(buf_path, 'rb')
                    buf_buf = buf_fd.read()
                    md5 = hashlib.md5(buf_buf).hexdigest()
                    if md5 == buf['md5']:
                        msg.debug('md5 sum matches. not getting buffer %s' % buf['path'])
                        if buf['encoding'] == 'utf8':
                            buf_buf = buf_buf.decode('utf-8')
                        buf['buf'] = buf_buf
                    elif self.should_get_bufs:
                        changed_bufs.append(buf_id)
                except Exception as e:
                    msg.debug('Error calculating md5:', e)
                    missing_bufs.append(buf_id)

        if changed_bufs and self.should_get_bufs:
            if len(changed_bufs) > 4:
                prompt = '%s local files are different from the workspace. Overwrite your local files?' % len(changed_bufs)
            else:
                prompt = 'Overwrite the following local files?\n'
                for buf_id in changed_bufs:
                    prompt += '\n%s' % self.bufs[buf_id]['path']

            stomp_local = yield self.ok_cancel_dialog, prompt
            for buf_id in changed_bufs:
                if stomp_local:
                    self.get_buf(buf_id)
                    self.save_on_get_bufs.add(buf_id)
                else:
                    buf = self.bufs[buf_id]
                    # TODO: this is inefficient. we just read the file 20 lines ago
                    self.upload(utils.get_full_path(buf['path']))

        for buf_id in missing_bufs:
            self.get_buf(buf_id)

        success_msg = 'Successfully joined workspace %s/%s' % (self.owner, self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace, self.workspace_url, G.PROJECT_PATH)
        self.emit("room_info")
Esempio n. 22
0
    def _on_room_info(self, data):
        self.reset()
        self.joined_workspace = True
        self.workspace_info = data
        G.PERMS = data['perms']

        if 'patch' not in data['perms']:
            no_perms_msg = '''You don't have permission to edit this workspace. All files will be read-only.'''
            msg.log('No patch permission. Setting buffers to read-only')
            if 'request_perm' in data['perms']:
                should_send = yield self.ok_cancel_dialog, no_perms_msg + '\nDo you want to request edit permission?'
                if should_send:
                    self.send({
                        'name': 'request_perms',
                        'perms': ['edit_room']
                    })
            else:
                editor.error_message(no_perms_msg)

        floo_json = {
            'url':
            utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'),
                               floo_json)

        changed_bufs = []
        missing_bufs = []
        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            buf_path = utils.get_full_path(buf['path'])
            new_dir = os.path.dirname(buf_path)
            utils.mkdir(new_dir)
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id

            view = self.get_view(buf_id)
            if view and not view.is_loading() and buf['encoding'] == 'utf8':
                view_text = view.get_text()
                view_md5 = hashlib.md5(view_text.encode('utf-8')).hexdigest()
                buf['buf'] = view_text
                buf['view'] = view
                G.VIEW_TO_HASH[view.native_id] = view_md5
                if view_md5 == buf['md5']:
                    msg.debug('md5 sum matches view. not getting buffer %s' %
                              buf['path'])
                else:
                    changed_bufs.append(buf_id)
                    buf['md5'] = view_md5
            else:
                try:
                    if buf['encoding'] == "utf8":
                        if io:
                            buf_fd = io.open(buf_path, 'Urt', encoding='utf8')
                            buf_buf = buf_fd.read()
                        else:
                            buf_fd = open(buf_path, 'rb')
                            buf_buf = buf_fd.read().decode('utf-8').replace(
                                '\r\n', '\n')
                        md5 = hashlib.md5(buf_buf.encode('utf-8')).hexdigest()
                    else:
                        buf_fd = open(buf_path, 'rb')
                        buf_buf = buf_fd.read()
                        md5 = hashlib.md5(buf_buf).hexdigest()
                    buf_fd.close()
                    buf['buf'] = buf_buf
                    if md5 == buf['md5']:
                        msg.debug('md5 sum matches. not getting buffer %s' %
                                  buf['path'])
                    else:
                        msg.debug(
                            'md5 differs. possibly getting buffer later %s' %
                            buf['path'])
                        changed_bufs.append(buf_id)
                        buf['md5'] = md5
                except Exception as e:
                    msg.debug('Error calculating md5 for %s, %s' %
                              (buf['path'], e))
                    missing_bufs.append(buf_id)

        stomp_local = self.should_get_bufs
        if stomp_local and (changed_bufs or missing_bufs):
            changed = [self.bufs[buf_id] for buf_id in changed_bufs]
            missing = [self.bufs[buf_id] for buf_id in missing_bufs]
            choice = yield self.stomp_prompt, changed, missing
            if choice not in [0, 1]:
                self.stop()
                return
            stomp_local = bool(choice)

        for buf_id in changed_bufs:
            buf = self.bufs[buf_id]
            if stomp_local:
                self.get_buf(buf_id, buf.get('view'))
                self.save_on_get_bufs.add(buf_id)
            else:
                self._upload(utils.get_full_path(buf['path']), buf['buf'])

        for buf_id in missing_bufs:
            buf = self.bufs[buf_id]
            if stomp_local:
                self.get_buf(buf_id, buf.get('view'))
                self.save_on_get_bufs.add(buf_id)
            else:
                self.send({
                    'name': 'delete_buf',
                    'id': buf['id'],
                })

        success_msg = 'Successfully joined workspace %s/%s' % (self.owner,
                                                               self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace,
                                               self.workspace_url,
                                               G.PROJECT_PATH)
        self.emit("room_info")
Esempio n. 23
0
    def _on_room_info(self, data):
        self.joined_workspace = True
        self.workspace_info = data
        G.PERMS = data['perms']

        self.proto.reset_retries()

        if G.OUTBOUND_FILTERING:
            msg.error(
                'Detected outbound port blocking! See https://floobits.com/help/network for more info.'
            )

        read_only = False
        if 'patch' not in data['perms']:
            read_only = True
            no_perms_msg = '''You don't have permission to edit this workspace. All files will be read-only.'''
            msg.log('No patch permission. Setting buffers to read-only')
            if 'request_perm' in data['perms']:
                should_send = yield self.ok_cancel_dialog, no_perms_msg + '\nDo you want to request edit permission?'
                # TODO: wait for perms to be OK'd/denied before uploading or bailing
                if should_send:
                    self.send({
                        'name': 'request_perms',
                        'perms': ['edit_room']
                    })
            else:
                if G.EXPERT_MODE:
                    editor.status_message(no_perms_msg)
                else:
                    editor.error_message(no_perms_msg)

        floo_json = {
            'url':
            utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'),
                               floo_json)
        utils.update_recent_workspaces(self.workspace_url)

        changed_bufs = []
        missing_bufs = []
        new_files = set()
        ig = ignore.create_ignore_tree(G.PROJECT_PATH)
        G.IGNORE = ig
        if not read_only:
            new_files = set([utils.to_rel_path(x) for x in ig.list_paths()])

        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            buf_path = utils.get_full_path(buf['path'])
            new_dir = os.path.dirname(buf_path)
            utils.mkdir(new_dir)
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id

            view = self.get_view(buf_id)
            if view and not view.is_loading() and buf['encoding'] == 'utf8':
                view_text = view.get_text()
                view_md5 = hashlib.md5(view_text.encode('utf-8')).hexdigest()
                buf['buf'] = view_text
                buf['view'] = view
                G.VIEW_TO_HASH[view.native_id] = view_md5
                if view_md5 == buf['md5']:
                    msg.debug('md5 sum matches view. not getting buffer ',
                              buf['path'])
                else:
                    changed_bufs.append(buf)
                    buf['md5'] = view_md5
                continue

            try:
                if buf['encoding'] == 'utf8':
                    if io:
                        buf_fd = io.open(buf_path, 'Urt', encoding='utf8')
                        buf_buf = buf_fd.read()
                    else:
                        buf_fd = open(buf_path, 'rb')
                        buf_buf = buf_fd.read().decode('utf-8').replace(
                            '\r\n', '\n')
                    md5 = hashlib.md5(buf_buf.encode('utf-8')).hexdigest()
                else:
                    buf_fd = open(buf_path, 'rb')
                    buf_buf = buf_fd.read()
                    md5 = hashlib.md5(buf_buf).hexdigest()
                buf_fd.close()
                buf['buf'] = buf_buf
                if md5 == buf['md5']:
                    msg.debug('md5 sum matches. not getting buffer ',
                              buf['path'])
                else:
                    msg.debug('md5 differs. possibly getting buffer later ',
                              buf['path'])
                    changed_bufs.append(buf)
                    buf['md5'] = md5
            except Exception as e:
                msg.debug('Error calculating md5 for ', buf['path'], ', ',
                          str_e(e))
                missing_bufs.append(buf)

        ignored = []
        for p, buf_id in self.paths_to_ids.items():
            if p not in new_files:
                ignored.append(p)
            new_files.discard(p)

        if self.action == utils.JOIN_ACTION.UPLOAD:
            yield self._initial_upload, ig, missing_bufs, changed_bufs
            # TODO: maybe use org name here
            who = 'Your friends'
            anon_perms = G.AGENT.workspace_info.get('anon_perms')
            if 'get_buf' in anon_perms:
                who = 'Anyone'
            _msg = 'You are sharing:\n\n%s\n\n%s can join your workspace at:\n\n%s' % (
                G.PROJECT_PATH, who, G.AGENT.workspace_url)
            # Workaround for horrible Sublime Text bug
            utils.set_timeout(editor.message_dialog, 0, _msg)
        elif changed_bufs or missing_bufs or new_files:
            # TODO: handle readonly here
            if self.action == utils.JOIN_ACTION.PROMPT:
                stomp_local = yield self.stomp_prompt, changed_bufs, missing_bufs, list(
                    new_files), ignored
                if stomp_local not in [0, 1]:
                    self.stop()
                    return
            elif self.action == utils.JOIN_ACTION.DOWNLOAD:
                stomp_local = True
            else:
                # This should never happen
                assert False
                return

            if stomp_local:
                for buf in changed_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
                for buf in missing_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
            else:
                yield self._initial_upload, ig, missing_bufs, changed_bufs

        success_msg = '%s@%s/%s: Joined!' % (self.username, self.owner,
                                             self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace,
                                               self.workspace_url,
                                               G.PROJECT_PATH)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        self.emit("room_info")
Esempio n. 24
0
    def _on_room_info(self, data):
        self.joined_workspace = True
        self.workspace_info = data
        G.PERMS = data['perms']

        self.proto.reset_retries()

        if G.OUTBOUND_FILTERING:
            msg.error(
                'Detected outbound port blocking! See https://floobits.com/help/network for more info.'
            )

        read_only = False
        if 'patch' not in data['perms']:
            read_only = True
            no_perms_msg = '''You don't have permission to edit this workspace. All files will be read-only.'''
            msg.log('No patch permission. Setting buffers to read-only')
            if 'request_perm' in data['perms']:
                should_send = yield self.ok_cancel_dialog, no_perms_msg + '\nDo you want to request edit permission?'
                # TODO: wait for perms to be OK'd/denied before uploading or bailing
                if should_send:
                    self.send({
                        'name': 'request_perms',
                        'perms': ['edit_room']
                    })
            else:
                if G.EXPERT_MODE:
                    editor.status_message(no_perms_msg)
                else:
                    editor.error_message(no_perms_msg)

        floo_json = {
            'url':
            utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'),
                               floo_json)
        utils.update_recent_workspaces(self.workspace_url)

        ig = ignore.create_ignore_tree(G.PROJECT_PATH)
        G.IGNORE = ig
        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id
        changed_bufs, missing_bufs, new_files = self._scan_dir(
            data['bufs'], ig, read_only)

        ignored = []
        for p, buf_id in self.paths_to_ids.items():
            if p not in new_files:
                ignored.append(p)
            new_files.discard(p)

        if self.action == utils.JOIN_ACTION.UPLOAD:
            yield self._initial_upload, ig, missing_bufs, changed_bufs
            # TODO: maybe use org name here
            who = 'Your friends'
            anon_perms = G.AGENT.workspace_info.get('anon_perms')
            if 'get_buf' in anon_perms:
                who = 'Anyone'
            _msg = 'You are sharing:\n\n%s\n\n%s can join your workspace at:\n\n%s' % (
                G.PROJECT_PATH, who, G.AGENT.workspace_url)
            # Workaround for horrible Sublime Text bug
            utils.set_timeout(editor.message_dialog, 0, _msg)
            # Don't auto-upload again on reconnect
            self.action = utils.JOIN_ACTION.PROMPT
        elif changed_bufs or missing_bufs or new_files:
            # TODO: handle readonly here
            if self.action == utils.JOIN_ACTION.PROMPT:
                stomp_local = yield self.stomp_prompt, changed_bufs, missing_bufs, list(
                    new_files), ignored
                if stomp_local not in [0, 1]:
                    self.stop()
                    return
            elif self.action == utils.JOIN_ACTION.DOWNLOAD:
                stomp_local = True
            else:
                # This should never happen
                assert False
                return

            if stomp_local:
                for buf in changed_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
                for buf in missing_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
            else:
                yield self._initial_upload, ig, missing_bufs, changed_bufs

        success_msg = '%s@%s/%s: Joined!' % (self.username, self.owner,
                                             self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace,
                                               self.workspace_url,
                                               G.PROJECT_PATH)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        if data.get('repo_info'):
            msg.log('Repo info:', data.get('repo_info'))
            # TODO: check local repo info and update remote (or prompt?)
        else:
            repo_info = repo.get_info(self.workspace_url, G.PROJECT_PATH)
            if repo_info and 'repo' in G.PERMS:
                self.send({
                    'name': 'repo',
                    'action': 'set',
                    'data': repo_info,
                })

        self.emit("room_info")
Esempio n. 25
0
    def _on_room_info(self, data):
        self.reset()
        self.joined_workspace = True
        self.workspace_info = data
        G.PERMS = data['perms']

        self.proto.reset_retries()

        if G.OUTBOUND_FILTERING:
            msg.error('Detected outbound port blocking! See https://floobits.com/help/network for more info.')

        read_only = False
        if 'patch' not in data['perms']:
            read_only = True
            no_perms_msg = '''You don't have permission to edit this workspace. All files will be read-only.'''
            msg.log('No patch permission. Setting buffers to read-only')
            if 'request_perm' in data['perms']:
                should_send = yield self.ok_cancel_dialog, no_perms_msg + '\nDo you want to request edit permission?'
                # TODO: wait for perms to be OK'd/denied before uploading or bailing
                if should_send:
                    self.send({'name': 'request_perms', 'perms': ['edit_room']})
            else:
                if G.EXPERT_MODE:
                    editor.status_message(no_perms_msg)
                else:
                    editor.error_message(no_perms_msg)

        floo_json = {
            'url': utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'), floo_json)
        utils.update_recent_workspaces(self.workspace_url)

        changed_bufs = []
        missing_bufs = []
        new_files = set()
        ig = ignore.create_ignore_tree(G.PROJECT_PATH)
        G.IGNORE = ig
        if not read_only:
            new_files = set([utils.to_rel_path(x) for x in ig.list_paths()])

        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            buf_path = utils.get_full_path(buf['path'])
            new_dir = os.path.dirname(buf_path)
            utils.mkdir(new_dir)
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id

            view = self.get_view(buf_id)
            if view and not view.is_loading() and buf['encoding'] == 'utf8':
                view_text = view.get_text()
                view_md5 = hashlib.md5(view_text.encode('utf-8')).hexdigest()
                buf['buf'] = view_text
                buf['view'] = view
                G.VIEW_TO_HASH[view.native_id] = view_md5
                if view_md5 == buf['md5']:
                    msg.debug('md5 sum matches view. not getting buffer ', buf['path'])
                else:
                    changed_bufs.append(buf)
                    buf['md5'] = view_md5
                continue

            try:
                if buf['encoding'] == 'utf8':
                    if io:
                        buf_fd = io.open(buf_path, 'Urt', encoding='utf8')
                        buf_buf = buf_fd.read()
                    else:
                        buf_fd = open(buf_path, 'rb')
                        buf_buf = buf_fd.read().decode('utf-8').replace('\r\n', '\n')
                    md5 = hashlib.md5(buf_buf.encode('utf-8')).hexdigest()
                else:
                    buf_fd = open(buf_path, 'rb')
                    buf_buf = buf_fd.read()
                    md5 = hashlib.md5(buf_buf).hexdigest()
                buf_fd.close()
                buf['buf'] = buf_buf
                if md5 == buf['md5']:
                    msg.debug('md5 sum matches. not getting buffer ', buf['path'])
                else:
                    msg.debug('md5 differs. possibly getting buffer later ', buf['path'])
                    changed_bufs.append(buf)
                    buf['md5'] = md5
            except Exception as e:
                msg.debug('Error calculating md5 for ', buf['path'], ', ', str_e(e))
                missing_bufs.append(buf)

        ignored = []
        for p, buf_id in self.paths_to_ids.items():
            if p not in new_files:
                ignored.append(p)
            new_files.discard(p)

        if self.action == utils.JOIN_ACTION.UPLOAD:
            yield self._initial_upload, ig, missing_bufs, changed_bufs
            # TODO: maybe use org name here
            who = 'Your friends'
            anon_perms = G.AGENT.workspace_info.get('anon_perms')
            if 'get_buf' in anon_perms:
                who = 'Anyone'
            _msg = 'You are sharing:\n\n%s\n\n%s can join your workspace at:\n\n%s' % (G.PROJECT_PATH, who, G.AGENT.workspace_url)
            # Workaround for horrible Sublime Text bug
            utils.set_timeout(editor.message_dialog, 0, _msg)
        elif changed_bufs or missing_bufs or new_files:
            # TODO: handle readonly here
            if self.action == utils.JOIN_ACTION.PROMPT:
                stomp_local = yield self.stomp_prompt, changed_bufs, missing_bufs, list(new_files), ignored
                if stomp_local not in [0, 1]:
                    self.stop()
                    return
            elif self.action == utils.JOIN_ACTION.DOWNLOAD:
                stomp_local = True
            else:
                # This should never happen
                assert False
                return

            if stomp_local:
                for buf in changed_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
                for buf in missing_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
            else:
                yield self._initial_upload, ig, missing_bufs, changed_bufs

        success_msg = 'Successfully joined workspace %s/%s' % (self.owner, self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace, self.workspace_url, G.PROJECT_PATH)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        self.emit("room_info")
Esempio n. 26
0
    def _on_room_info(self, data):
        self.joined_workspace = True
        self.workspace_info = data
        G.PERMS = data['perms']

        self.proto.reset_retries()

        if G.OUTBOUND_FILTERING:
            msg.error('Detected outbound port blocking! See https://floobits.com/help/network for more info.')

        read_only = False
        if 'patch' not in data['perms']:
            read_only = True
            no_perms_msg = '''You don't have permission to edit this workspace. All files will be read-only.'''
            msg.log('No patch permission. Setting buffers to read-only')
            if 'request_perm' in data['perms']:
                should_send = yield self.ok_cancel_dialog, no_perms_msg + '\nDo you want to request edit permission?'
                # TODO: wait for perms to be OK'd/denied before uploading or bailing
                if should_send:
                    self.send({'name': 'request_perms', 'perms': ['edit_room']})
            else:
                if G.EXPERT_MODE:
                    editor.status_message(no_perms_msg)
                else:
                    editor.error_message(no_perms_msg)

        floo_json = {
            'url': utils.to_workspace_url({
                'owner': self.owner,
                'workspace': self.workspace,
                'host': self.proto.host,
                'port': self.proto.port,
                'secure': self.proto.secure,
            })
        }
        utils.update_floo_file(os.path.join(G.PROJECT_PATH, '.floo'), floo_json)
        utils.update_recent_workspaces(self.workspace_url)

        ig = ignore.create_ignore_tree(G.PROJECT_PATH)
        G.IGNORE = ig
        for buf_id, buf in data['bufs'].items():
            buf_id = int(buf_id)  # json keys must be strings
            self.bufs[buf_id] = buf
            self.paths_to_ids[buf['path']] = buf_id
        changed_bufs, missing_bufs, new_files = self._scan_dir(data['bufs'], ig, read_only)

        ignored = []
        for p, buf_id in self.paths_to_ids.items():
            if p not in new_files:
                ignored.append(p)
            new_files.discard(p)

        if self.action == utils.JOIN_ACTION.UPLOAD:
            yield self._initial_upload, ig, missing_bufs, changed_bufs
            # TODO: maybe use org name here
            who = 'Your friends'
            anon_perms = G.AGENT.workspace_info.get('anon_perms')
            if 'get_buf' in anon_perms:
                who = 'Anyone'
            _msg = 'You are sharing:\n\n%s\n\n%s can join your workspace at:\n\n%s' % (G.PROJECT_PATH, who, G.AGENT.workspace_url)
            # Workaround for horrible Sublime Text bug
            utils.set_timeout(editor.message_dialog, 0, _msg)
            # Don't auto-upload again on reconnect
            self.action = utils.JOIN_ACTION.PROMPT
        elif changed_bufs or missing_bufs or new_files:
            # TODO: handle readonly here
            if self.action == utils.JOIN_ACTION.PROMPT:
                stomp_local = yield self.stomp_prompt, changed_bufs, missing_bufs, list(new_files), ignored
                if stomp_local not in [0, 1]:
                    self.stop()
                    return
            elif self.action == utils.JOIN_ACTION.DOWNLOAD:
                stomp_local = True
            else:
                # This should never happen
                assert False
                return

            if stomp_local:
                for buf in changed_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
                for buf in missing_bufs:
                    self.get_buf(buf['id'], buf.get('view'))
                    self.save_on_get_bufs.add(buf['id'])
            else:
                yield self._initial_upload, ig, missing_bufs, changed_bufs

        success_msg = '%s@%s/%s: Joined!' % (self.username, self.owner, self.workspace)
        msg.log(success_msg)
        editor.status_message(success_msg)

        data = utils.get_persistent_data()
        data['recent_workspaces'].insert(0, {"url": self.workspace_url})
        utils.update_persistent_data(data)
        utils.add_workspace_to_persistent_json(self.owner, self.workspace, self.workspace_url, G.PROJECT_PATH)

        temp_data = data.get('temp_data', {})
        hangout = temp_data.get('hangout', {})
        hangout_url = hangout.get('url')
        if hangout_url:
            self.prompt_join_hangout(hangout_url)

        if data.get('repo_info'):
            msg.log('Repo info:', data.get('repo_info'))
            # TODO: check local repo info and update remote (or prompt?)
        else:
            repo_info = repo.get_info(self.workspace_url, G.PROJECT_PATH)
            if repo_info and 'repo' in G.PERMS:
                self.send({
                    'name': 'repo',
                    'action': 'set',
                    'data': repo_info,
                })

        self.emit("room_info")