class Turpial: '''Inicio de Turpial''' def __init__(self): parser = OptionParser() parser.add_option('-d', '--debug', dest='debug', action='store_true', help='Debug Mode', default=False) parser.add_option('-i', '--interface', dest='interface', help='Select interface to use. (cmd|gtk)', default='gtk') parser.add_option('-c', '--clean', dest='clean', action='store_true', help='Clean all bytecodes', default=False) parser.add_option('--test', dest='test', action='store_true', help='Test mode. Only load timeline', default=False) (options, _) = parser.parse_args() self.config = None self.global_cfg = ConfigApp() self.profile = None self.remember = False self.testmode = options.test if options.debug: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.INFO) self.log = logging.getLogger('Controller') if options.clean: self.__clean() self.signout() self.interface = options.interface #if options.interface == 'gtk2': # self.ui = gtk2_ui_main.Main(self) if options.interface == 'gtk+': self.ui = _GTK(self, extend=True) elif options.interface == 'gtk': self.ui = _GTK(self) else: print 'No existe tal interfaz. Saliendo...' sys.exit(-1) self.httpserv = HTTPServices() self.api = TurpialAPI() self.log.debug('Iniciando Turpial') self.httpserv.start() self.api.start() self.api.change_api_url(self.global_cfg.read('Proxy', 'url')) if self.testmode: self.log.debug('Modo Pruebas Activado') self.ui.show_login(self.global_cfg) self.ui.main_loop() def __clean(self): '''Limpieza de ficheros .pyc y .pyo''' self.log.debug("Limpiando la casa...") i = 0 for root, dirs, files in os.walk('.'): for f in files: path = os.path.join(root, f) if path.endswith('.pyc') or path.endswith('.pyo'): self.log.debug("Borrado %s" % path) os.remove(path) def __validate_signin(self, val): '''Chequeo de inicio de sesion''' if val.has_key('error'): self.ui.cancel_login(val['error']) else: self.profile = val self.ui.update_user_profile(val) self.ui.show_main(self.config, self.global_cfg, val) self._update_timeline() if self.testmode: return self._update_replies() self._update_directs() self._update_favorites() self._update_rate_limits() def __validate_credentials(self, val): '''Chequeo de credenciales''' if val.has_key('error'): self.ui.cancel_login(val['error']) else: self.profile = val self.config = ConfigHandler(val['screen_name']) if self.remember: self.global_cfg.write('Login', 'username', self.api.username) self.global_cfg.write('Login', 'password', base64.b64encode(self.api.password)) else: self.global_cfg.write('Login', 'username', '') self.global_cfg.write('Login', 'password', '') self.httpserv.update_img_dir(self.config.imgdir) self.httpserv.set_credentials(self.api.username, self.api.password) auth = self.config.read_section('Auth') if self.api.has_oauth_support(): self.api.start_oauth(auth, self.ui.show_oauth_pin_request, self.__signin_done) else: self.api.is_oauth = False self.__signin_done(None, None, None) def __done_follow(self, friends, profile, user, follow): self.ui.update_user_profile(profile) self.ui.update_friends(friends) self.ui.update_follow(user, follow) #self.ui.update_timeline(friends) def __direct_done(self, tweet): self.ui.tweet_done(tweet) def __tweet_done(self, tweet): if tweet: self.profile['statuses_count'] += 1 self.ui.update_user_profile(self.profile) self.ui.tweet_done(tweet) def __signin_done(self, key, secret, verifier): '''Inicio de sesion finalizado''' if key is not None: self.config.write('Auth', 'oauth-key', key) if secret is not None: self.config.write('Auth', 'oauth-secret', secret) if verifier is not None: self.config.write('Auth', 'oauth-verifier', verifier) self.api.muted_users = self.config.load_muted_list() self.ui.show_main(self.config, self.global_cfg, self.profile) self._update_timeline() if self.testmode: return self._update_replies() self._update_directs() self._update_rate_limits() self._update_favorites() self._update_friends() def _update_timeline(self): '''Actualizar linea de tiempo''' self.ui.start_updating_timeline() tweets = int(self.config.read('General', 'num-tweets')) self.api.update_timeline(self.ui.update_timeline, tweets) def _update_replies(self): '''Actualizar numero de respuestas''' self.ui.start_updating_replies() tweets = int(self.config.read('General', 'num-tweets')) self.api.update_replies(self.ui.update_replies, tweets) def _update_directs(self): '''Actualizar mensajes directos''' self.ui.start_updating_directs() tweets = int(self.config.read('General', 'num-tweets')) self.api.update_directs(self.ui.update_directs, tweets) def _update_favorites(self): '''Actualizar favoritos''' self.api.update_favorites(self.ui.update_favorites) def _update_rate_limits(self): self.api.update_rate_limits(self.ui.update_rate_limits) def _update_friends(self): '''Actualizar amigos''' self.api.get_friends(self.ui.update_friends) def signin(self, username, password): self.config = ConfigHandler(username) self.api.auth(username, password, self.__validate_signin) def signin_oauth(self, username, password, remember): self.remember = remember self.api.auth(username, password, self.__validate_credentials) def auth_token(self, pin): self.api.authorize_oauth_token(pin, self.__signin_done) def signout(self): '''Finalizar sesion''' self.save_muted_list() self.log.debug('Desconectando') exit(0) #self.httpserv.quit() #if self.profile: # self.api.end_session() #else: # self.api.quit() def update_status(self, text, reply_id=None): if text.startswith('D '): self.api.update_status(text, reply_id, self.__direct_done) else: self.api.update_status(text, reply_id, self.__tweet_done) def destroy_status(self, tweet_id): self.api.destroy_status(tweet_id, self.ui.after_destroy) def set_favorite(self, tweet_id): self.api.set_favorite(tweet_id, self.ui.update_favorites) def unset_favorite(self, tweet_id): self.api.unset_favorite(tweet_id, self.ui.update_favorites) def retweet(self, tweet_id): self.api.retweet(tweet_id, self.ui.tweet_changed) def follow(self, user): self.api.follow(user, self.__done_follow) def unfollow(self, user): self.api.unfollow(user, self.__done_follow) def update_profile(self, new_name, new_url, new_bio, new_location): self.api.update_profile(new_name, new_url, new_bio, new_location, self.ui.update_user_profile) def in_reply_to(self, twt_id): self.api.in_reply_to(twt_id, self.ui.update_in_reply_to) def get_conversation(self, twt_id): self.api.get_conversation(twt_id, self.ui.update_conversation) def mute(self, user): self.ui.start_updating_timeline() self.api.mute(user, self.ui.update_timeline) def short_url(self, text, callback): service = self.config.read('Services', 'shorten-url') self.httpserv.short_url(service, text, callback) def download_user_pic(self, user, pic_url, callback): self.httpserv.download_pic(user, pic_url, callback) def upload_pic(self, path, callback): service = self.config.read('Services', 'upload-pic') self.httpserv.upload_pic(service, path, callback) def search_topic(self, query): self.ui.start_search() self.api.search_topic(query, self.ui.update_search_topics) def get_popup_info(self, tweet_id, user): if tweet_id in self.api.to_fav: return {'busy': 'Marcando favorito...'} elif tweet_id in self.api.to_unfav: return {'busy': 'Desmarcando favorito...'} elif tweet_id in self.api.to_del: return {'busy': 'Borrando...'} rtn = {} if self.api.friendsloaded: rtn['friend'] = self.api.is_friend(user) rtn['fav'] = self.api.is_fav(tweet_id) rtn['own'] = (self.profile['screen_name'] == user) return rtn def save_config(self, config, update): self.config.save(config) if update: self.ui.update_config(self.config) def save_global_config(self, config): self.global_cfg.save(config) def save_muted_list(self): if self.config: self.config.save_muted_list(self.api.muted_users) def get_muted_list(self): return self.api.get_muted_list() def update_muted(self, muted_users): self.ui.start_updating_timeline() timeline = self.api.mute(muted_users, self.ui.update_timeline) def destroy_direct(self, tweet_id): self.api.destroy_direct(tweet_id, self.ui.after_destroy) def get_friends(self): return self.api.get_single_friends_list()
class Turpial: """Inicio de Turpial""" def __init__(self): ui_avail = "(" for ui in INTERFACES: ui_avail += ui + "|" ui_avail = ui_avail[:-1] + ")" default_ui = INTERFACES[1] if len(INTERFACES) > 1 else "" parser = OptionParser() parser.add_option( "-d", "--debug", dest="debug", action="store_true", help="show debug info in shell during execution", default=False, ) parser.add_option( "-i", "--interface", dest="interface", help="select interface to use %s" % ui_avail, default=default_ui ) parser.add_option("-c", "--clean", dest="clean", action="store_true", help="clean all bytecodes", default=False) parser.add_option( "-s", "--save-credentials", dest="save", action="store_true", help="save user credentials", default=False ) parser.add_option( "--version", dest="version", action="store_true", help="show the version of Turpial and exit", default=False ) parser.add_option( "--test", dest="test", action="store_true", help="only load timeline and friends", default=False ) parser.add_option( "--no-sound", dest="no_sound", action="store_true", help="disable the sounds module", default=False ) parser.add_option( "--no-notif", dest="no_notif", action="store_true", help="disable the notifications module", default=False ) (options, args) = parser.parse_args() self.config = None self.global_cfg = ConfigApp() self.protocol_cfg = {} self.profile = None self.testmode = options.test self.interface = options.interface self.no_sound = options.no_sound self.no_notif = options.no_notif self.httpserv = None self.api = None self.version = self.global_cfg.read("App", "version") for p in PROTOCOLS: self.protocol_cfg[p] = ConfigProtocol(p) if options.debug or options.clean: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.INFO) self.log = logging.getLogger("Controller") if options.clean: self.__clean() sys.exit(0) if options.version: print "Turpial v%s" % self.version print "Python v%X" % sys.hexversion sys.exit(0) if options.save: try: self.__save_credentials() except KeyboardInterrupt: self.log.debug("Interceptado Keyboard Interrupt") sys.exit(0) self.interface = options.interface if options.interface == "gtk+" and ("gtk+" in INTERFACES): self.ui = _GTK(self, extend=True) elif options.interface == "gtk" and ("gtk" in INTERFACES): self.ui = _GTK(self) elif options.interface == "cmd" and ("cmd" in INTERFACES): self.ui = _CMD(self, args) else: print "No existe una interfaz válida. Las interfaces válidas son: %s" % INTERFACES print "Saliendo..." sys.exit(-1) self.httpserv = HTTPServices() self.api = TurpialAPI() self.log.debug("Iniciando Turpial v%s" % self.version) if self.interface != "cmd": self.httpserv.start() self.api.start() self.api.change_api_url(self.global_cfg.read("Proxy", "url")) if self.testmode: self.log.debug("Modo Pruebas Activado") self.ui.show_login() try: self.ui.main_loop() except KeyboardInterrupt: self.log.debug("Interceptado Keyboard Interrupt") self.ui.main_quit() def __clean(self): """Limpieza de ficheros .pyc y .pyo""" self.log.debug("Limpiando la casa...") path = os.path.join(os.path.dirname(__file__)) i = 0 for root, dirs, files in os.walk(path): for f in files: path = os.path.join(root, f) if path.endswith(".pyc") or path.endswith(".pyo"): self.log.debug("Borrado %s" % path) os.remove(path) def __save_credentials(self): print "This assistant will allow you store your credentials" print "Available protocols" print "===================" for i in range(len(PROTOCOLS)): print "%d - %s" % (i, PROTOCOLS[i]) while 1: protocol = int(raw_input("Select protocol: ")) if protocol <= len(PROTOCOLS): break else: print "Invalid protocol, please try again" user, passwd, rem = self.get_remembered(protocol) if user != "" and passwd != "": delete = raw_input("Delete your current credentials (%s)? [Y/n/q]: " % user) if delete == "" or delete.lower() == "y": self.remember(pro=protocol, rem=False) return elif delete.lower() == "q": return user = raw_input("User: "******"Password: "******"Retype password: "******"Password mismatch, please try again" self.remember(user, passwd, protocol, True) print "Credentials saved successfully" def __validate_credentials(self, val, key, secret, protocol): """Chequeo de credenciales""" if val.type == "error": self.ui.cancel_login(val.errmsg) elif val.type == "profile": self.profile = val.items self.config = ConfigHandler(self.profile.username, protocol) self.config.initialize() self.current_protocol = protocol self.httpserv.update_img_dir(self.config.imgdir) self.httpserv.set_credentials(self.profile.username, self.profile.password, self.api.protocol.http) self.__signin_done(key, secret, val) def __done_follow(self, response): user = response.items[1] follow = response.items[2] if response.type == "error": msg = response.errmsg % user self.ui.following_error(msg, follow) elif response.type == "mixed": self.profile = response.items[0] self.ui.update_user_profile(self.profile) self.ui.update_follow(user, follow) def __direct_done(self, status): self.ui.tweet_done(status) def __tweet_done(self, status): if status: self.profile.statuses_count += 1 self.ui.update_user_profile(self.profile) self.ui.tweet_done(status) def __signin_done(self, key, secret, resp_profile): """Inicio de sesion finalizado""" # TODO: Llenar con el resto de listas self.lists = { "timeline": MicroBloggingList("timeline", "", _("Timeline"), _("tweet"), _("tweets")), "replies": MicroBloggingList("replies", "", _("Replies"), _("mention"), _("mentions")), "directs": MicroBloggingList("directs", "", _("Directs"), _("direct"), _("directs")), "sent": MicroBloggingList("sent", "", _("My Tweets"), _("tweet"), _("tweets")), } if self.interface != "cmd": plists = self.api.get_lists() for ls in plists: self.lists[str(ls.id)] = MicroBloggingList(str(ls.id), ls.user, ls.name, _("tweet"), _("tweets")) # Evita que la aplicación reviente si se borra una lista por fuera try: column1 = self.lists[self.config.read("Columns", "column1")] except KeyError: self.log.debug("La lista %s no existe. Se carga el Timeline" % self.config.read("Columns", "column1")) column1 = self.lists["timeline"] try: column2 = self.lists[self.config.read("Columns", "column2")] except KeyError: self.log.debug("La lista %s no existe. Se carga el Timeline" % self.config.read("Columns", "column2")) column2 = self.lists["timeline"] try: column3 = self.lists[self.config.read("Columns", "column3")] except KeyError: self.log.debug("La lista %s no existe. Se carga el Timeline" % self.config.read("Columns", "column3")) column3 = self.lists["timeline"] self.viewed_cols = [column1, column2, column3] self.api.protocol.muted_users = self.config.load_muted_list() self.ui.set_lists(self.lists, self.viewed_cols) self.ui.show_main(self.config, self.global_cfg, resp_profile) if self.interface == "cmd": return self._update_column1() if self.testmode: self._update_rate_limits() self._update_friends() return self._update_column2() self._update_column3() self._update_rate_limits() self._update_favorites() self._update_friends() def _update_column1(self): """Actualizar columna 1""" self.ui.start_updating_column1() count = int(self.config.read("General", "num-tweets")) column = self.viewed_cols[0] self.api.update_column(self.ui.update_column1, count, column) def _update_column2(self): """Actualizar columna 2""" self.ui.start_updating_column2() count = int(self.config.read("General", "num-tweets")) column = self.viewed_cols[1] self.api.update_column(self.ui.update_column2, count, column) def _update_column3(self): """Actualizar columna 3""" self.ui.start_updating_column3() count = int(self.config.read("General", "num-tweets")) column = self.viewed_cols[2] self.api.update_column(self.ui.update_column3, count, column) def _update_favorites(self): """Actualizar favoritos""" self.api.update_favorites(self.ui.update_favorites) def _update_rate_limits(self): self.api.update_rate_limits(self.ui.update_rate_limits) def _update_friends(self): """Actualizar amigos""" self.api.get_friends() def get_remembered(self, index): protocol = PROTOCOLS[index] us = self.protocol_cfg[protocol].read("Login", "username") pw = self.protocol_cfg[protocol].read("Login", "password") try: if us != "" and pw != "": a = base64.b64decode(pw) b = a[1:-1] c = base64.b32decode(b) d = c[1:-1] e = base64.b16decode(d) pwd = e[0 : len(us)] + e[len(us) :] return us, pwd, True else: return us, pw, False except TypeError: self.protocol_cfg[protocol].write("Login", "username", "") self.protocol_cfg[protocol].write("Login", "password", "") return "", "", False def remember(self, us="", pw="", pro=0, rem=False): protocol = PROTOCOLS[pro] if not rem: self.protocol_cfg[protocol].write("Login", "username", "") self.protocol_cfg[protocol].write("Login", "password", "") return a = base64.b16encode(pw) b = us[0] + a + ("%s" % us[-1]) c = base64.b32encode(b) d = ("%s" % us[-1]) + c + us[0] e = base64.b64encode(d) pwd = e[0 : len(us)] + e[len(us) :] self.protocol_cfg[protocol].write("Login", "username", us) self.protocol_cfg[protocol].write("Login", "password", pwd) def signin(self, username, password, protocol): config = ConfigHandler(username, protocol) config.initialize_failsafe() auth = config.read_section("Auth") self.api.auth(username, password, auth, protocol, self.__validate_credentials) def signout(self): """Finalizar sesion""" self.save_muted_list() self.log.debug("Desconectando") if self.httpserv and self.interface != "cmd": self.httpserv.quit() self.httpserv.join(0) if self.api: self.api.quit() if self.interface != "cmd": self.api.join(0) sys.exit(0) def update_status(self, text, reply_id=None): if text.startswith("D "): self.api.update_status(text, reply_id, self.__direct_done) else: self.api.update_status(text, reply_id, self.__tweet_done) def destroy_status(self, id): self.api.destroy_status(id, self.ui.after_destroy_status) def set_favorite(self, id): self.api.set_favorite(id, self.ui.tweet_changed) def unset_favorite(self, id): self.api.unset_favorite(id, self.ui.tweet_changed) def repeat(self, id): self.api.repeat(id, self.__tweet_done) def follow(self, user): self.api.follow(user, self.__done_follow) def unfollow(self, user): self.api.unfollow(user, self.__done_follow) def update_profile(self, new_name, new_url, new_bio, new_location): self.api.update_profile(new_name, new_url, new_bio, new_location, self.ui.update_user_profile) def in_reply_to(self, id): self.api.in_reply_to(id, self.ui.update_in_reply_to) def get_conversation(self, id): self.api.get_conversation(id, self.ui.update_conversation) def mute(self, users): self.api.mute(users, self.ui.tweet_changed) def short_url(self, text, callback): service = self.config.read("Services", "shorten-url") self.httpserv.short_url(service, text, callback) def download_user_pic(self, user, pic_url, callback): self.httpserv.download_pic(user, pic_url, callback) def upload_pic(self, path, message, callback): service = self.config.read("Services", "upload-pic") self.httpserv.upload_pic(service, path, message, callback) def search(self, query): self.ui.start_search() self.api.search(query, self.ui.update_search) def get_popup_info(self, tweet_id, user): if self.api.is_marked_to_fav(tweet_id): return {"marking_fav": True} elif self.api.is_marked_to_unfav(tweet_id): return {"unmarking_fav": True} elif self.api.is_marked_to_del(tweet_id): return {"deleting": True} rtn = {} if self.api.friends_loaded(): rtn["friend"] = self.api.is_friend(user) rtn["fav"] = self.api.is_fav(tweet_id) return rtn def save_config(self, config, update): self.config.save(config) if update: self.ui.update_config(self.config) def save_global_config(self, config): self.global_cfg.save(config) def save_muted_list(self): if self.config: self.config.save_muted_list(self.api.protocol.muted_users) def get_muted_list(self): return self.api.get_muted_list() def destroy_direct(self, id): self.api.destroy_direct(id, self.ui.after_destroy_direct) def get_friends(self): return self.api.get_single_friends_list() def get_hashtags_url(self): return self.api.protocol.tags_url def get_groups_url(self): return self.api.protocol.groups_url # FIXME: Debería pasarse como parámetro el protocolo def get_profiles_url(self): return self.api.protocol.profiles_url def get_viewed_columns(self): return self.viewed_cols def change_column(self, index, new_id): print "change_column", self.lists.keys(), index, new_id if self.lists.has_key(new_id): self.viewed_cols[index] = self.lists[new_id] if index == 0: self._update_column1() elif index == 1: self._update_column2() elif index == 2: self._update_column3() else: self.ui.set_column_item(index, reset=True) self.log.debug("Error: la columna %s no existe" % new_id) def is_friend(self, user): return self.api.is_friend(user)
class Turpial: '''Inicio de Turpial''' def __init__(self): parser = OptionParser() parser.add_option('-d', '--debug', dest='debug', action='store_true', help='Debug Mode', default=False) parser.add_option('-i', '--interface', dest='interface', help='Select interface to use. (cmd|gtk)', default='gtk') parser.add_option('-c', '--clean', dest='clean', action='store_true', help='Clean all bytecodes', default=False) parser.add_option('--test', dest='test', action='store_true', help='Test mode. Only load timeline', default=False) (options, _) = parser.parse_args() self.config = None self.global_cfg = ConfigApp() self.profile = None self.remember = False self.testmode = options.test self.httpserv = None self.api = None if options.debug: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.INFO) self.log = logging.getLogger('Controller') if options.clean: self.__clean() self.signout() self.interface = options.interface if options.interface == 'gtk+': self.ui = _GTK(self, extend=True) elif options.interface == 'gtk': self.ui = _GTK(self) else: print 'No existe tal interfaz. Saliendo...' sys.exit(-1) self.httpserv = HTTPServices() self.api = TurpialAPI() self.log.debug('Iniciando Turpial') self.httpserv.start() self.api.start() self.api.change_api_url(self.global_cfg.read('Proxy', 'url')) if self.testmode: self.log.debug('Modo Pruebas Activado') self.ui.show_login(self.global_cfg) self.ui.main_loop() def __clean(self): '''Limpieza de ficheros .pyc y .pyo''' self.log.debug("Limpiando la casa...") i = 0 for root, dirs, files in os.walk('.'): for f in files: path = os.path.join(root, f) if path.endswith('.pyc') or path.endswith('.pyo'): self.log.debug("Borrado %s" % path) os.remove(path) def __validate_signin(self, val): '''Chequeo de inicio de sesion''' if val.has_key('error'): self.ui.cancel_login(val['error']) else: self.profile = val self.ui.update_user_profile(val) self.ui.show_main(self.config, self.global_cfg, val) self._update_timeline() if self.testmode: return self._update_replies() self._update_directs() self._update_favorites() self._update_rate_limits() def __validate_credentials(self, val): '''Chequeo de credenciales''' if val.has_key('error'): self.ui.cancel_login(val['error']) else: if self.api.has_oauth_support(): self.api.validate_credentials(self.__signin_done) else: self.api.is_oauth = False self.__signin_done(None, None, None) def __done_follow(self, friends, profile, user, follow): self.ui.update_user_profile(profile) self.ui.update_friends(friends) self.ui.update_follow(user, follow) #self.ui.update_timeline(friends) def __direct_done(self, tweet): self.ui.tweet_done(tweet) def __tweet_done(self, tweet): if tweet: self.profile['statuses_count'] += 1 self.ui.update_user_profile(self.profile) self.ui.tweet_done(tweet) def __signin_done(self, val): '''Inicio de sesion finalizado''' if val.has_key('error'): self.ui.cancel_login(val['error']) else: self.profile = val self.config = ConfigHandler(val['screen_name']) if self.remember: self.global_cfg.write('Login', 'username', self.api.username) self.global_cfg.write('Login', 'password', base64.b64encode(self.api.password)) else: self.global_cfg.write('Login', 'username', '') self.global_cfg.write('Login', 'password', '') self.httpserv.update_img_dir(self.config.imgdir) self.httpserv.set_credentials(self.api.username, self.api.password) self.api.muted_users = self.config.load_muted_list() self.ui.show_main(self.config, self.global_cfg, self.profile) self._update_timeline() if self.testmode: return self._update_replies() self._update_directs() self._update_rate_limits() self._update_favorites() self._update_friends() def _update_timeline(self): '''Actualizar linea de tiempo''' self.ui.start_updating_timeline() tweets = int(self.config.read('General', 'num-tweets')) self.api.update_timeline(self.ui.update_timeline, tweets) def _update_replies(self): '''Actualizar numero de respuestas''' self.ui.start_updating_replies() tweets = int(self.config.read('General', 'num-tweets')) self.api.update_replies(self.ui.update_replies, tweets) def _update_directs(self): '''Actualizar mensajes directos''' self.ui.start_updating_directs() tweets = int(self.config.read('General', 'num-tweets')) self.api.update_directs(self.ui.update_directs, tweets) def _update_favorites(self): '''Actualizar favoritos''' self.api.update_favorites(self.ui.update_favorites) def _update_rate_limits(self): self.api.update_rate_limits(self.ui.update_rate_limits) def _update_friends(self): '''Actualizar amigos''' self.api.get_friends(self.ui.update_friends) def signin(self, username, password): self.config = ConfigHandler(username) self.api.auth(username, password, self.__validate_signin) def signin_oauth(self, username, password, remember): self.remember = remember self.api.auth(username, password, self.__validate_credentials) def auth_token(self, pin): self.api.authorize_oauth_token(pin, self.__signin_done) def signout(self): '''Finalizar sesion''' self.save_muted_list() self.log.debug('Desconectando') if self.httpserv: self.httpserv.quit() self.httpserv.join() if self.api: self.api.quit() self.api.join() sys.exit(0) def update_status(self, text, reply_id=None): if text.startswith('D '): self.api.update_status(text, reply_id, self.__direct_done) else: self.api.update_status(text, reply_id, self.__tweet_done) def destroy_status(self, tweet_id): self.api.destroy_status(tweet_id, self.ui.after_destroy) def set_favorite(self, tweet_id): self.api.set_favorite(tweet_id, self.ui.update_favorites) def unset_favorite(self, tweet_id): self.api.unset_favorite(tweet_id, self.ui.update_favorites) def retweet(self, tweet_id): self.api.retweet(tweet_id, self.ui.tweet_changed) def follow(self, user): self.api.follow(user, self.__done_follow) def unfollow(self, user): self.api.unfollow(user, self.__done_follow) def update_profile(self, new_name, new_url, new_bio, new_location): self.api.update_profile(new_name, new_url, new_bio, new_location, self.ui.update_user_profile) def in_reply_to(self, twt_id): self.api.in_reply_to(twt_id, self.ui.update_in_reply_to) def get_conversation(self, twt_id): self.api.get_conversation(twt_id, self.ui.update_conversation) def mute(self, user): self.ui.start_updating_timeline() self.api.mute(user, self.ui.update_timeline) def short_url(self, text, callback): service = self.config.read('Services', 'shorten-url') self.httpserv.short_url(service, text, callback) def download_user_pic(self, user, pic_url, callback): self.httpserv.download_pic(user, pic_url, callback) def upload_pic(self, path, callback): service = self.config.read('Services', 'upload-pic') self.httpserv.upload_pic(service, path, callback) def search_topic(self, query): self.ui.start_search() self.api.search_topic(query, self.ui.update_search_topics) def get_popup_info(self, tweet_id, user): if tweet_id in self.api.to_fav: return {'busy': 'Marcando favorito...'} elif tweet_id in self.api.to_unfav: return {'busy': 'Desmarcando favorito...'} elif tweet_id in self.api.to_del: return {'busy': 'Borrando...'} rtn = {} if self.api.friendsloaded: rtn['friend'] = self.api.is_friend(user) rtn['fav'] = self.api.is_fav(tweet_id) rtn['own'] = (self.profile['screen_name'] == user) return rtn def save_config(self, config, update): self.config.save(config) if update: self.ui.update_config(self.config) def save_global_config(self, config): self.global_cfg.save(config) def save_muted_list(self): if self.config: self.config.save_muted_list(self.api.muted_users) def get_muted_list(self): return self.api.get_muted_list() def update_muted(self, muted_users): self.ui.start_updating_timeline() timeline = self.api.mute(muted_users, self.ui.update_timeline) def destroy_direct(self, tweet_id): self.api.destroy_direct(tweet_id, self.ui.after_destroy) def get_friends(self): return self.api.get_single_friends_list()
class Turpial: '''Inicio de Turpial''' def __init__(self): ui_avail = '(' for ui in INTERFACES: ui_avail += ui + '|' ui_avail = ui_avail[:-1] + ')' default_ui = INTERFACES[1] if len(INTERFACES) > 1 else '' parser = OptionParser() parser.add_option('-d', '--debug', dest='debug', action='store_true', help='show debug info in shell during execution', default=False) parser.add_option('-i', '--interface', dest='interface', help='select interface to use %s' % ui_avail, default=default_ui) parser.add_option('-c', '--clean', dest='clean', action='store_true', help='clean all bytecodes', default=False) parser.add_option('-s', '--save-credentials', dest='save', action='store_true', help='save user credentials', default=False) parser.add_option('--version', dest='version', action='store_true', help='show the version of Turpial and exit', default=False) parser.add_option('--test', dest='test', action='store_true', help='only load timeline and friends', default=False) parser.add_option('--no-sound', dest='no_sound', action='store_true', help='disable the sounds module', default=False) parser.add_option('--no-notif', dest='no_notif', action='store_true', help='disable the notifications module', default=False) (options, args) = parser.parse_args() self.config = None self.global_cfg = ConfigApp() self.protocol_cfg = {} self.profile = None self.testmode = options.test self.interface = options.interface self.no_sound = options.no_sound self.no_notif = options.no_notif self.httpserv = None self.api = None self.version = self.global_cfg.read('App', 'version') for p in PROTOCOLS: self.protocol_cfg[p] = ConfigProtocol(p) if options.debug or options.clean: logging.basicConfig(level=logging.DEBUG) else: logging.basicConfig(level=logging.INFO) self.log = logging.getLogger('Controller') if options.clean: self.__clean() sys.exit(0) if options.version: print "Turpial v%s" % self.version print "Python v%X" % sys.hexversion sys.exit(0) if options.save: try: self.__save_credentials() except KeyboardInterrupt: self.log.debug('Interceptado Keyboard Interrupt') sys.exit(0) self.interface = options.interface if options.interface == 'gtk+' and ('gtk+' in INTERFACES): self.ui = _GTK(self, extend=True) elif options.interface == 'gtk' and ('gtk' in INTERFACES): self.ui = _GTK(self) elif options.interface == 'cmd' and ('cmd' in INTERFACES): self.ui = _CMD(self, args) else: print 'No existe una interfaz válida. Las interfaces válidas son: %s' % INTERFACES print 'Saliendo...' sys.exit(-1) self.httpserv = HTTPServices() self.api = TurpialAPI() self.log.debug('Iniciando Turpial v%s' % self.version) if self.interface != 'cmd': self.httpserv.start() self.api.start() self.api.change_api_url(self.global_cfg.read('Proxy', 'url')) if self.testmode: self.log.debug('Modo Pruebas Activado') self.ui.show_login() try: self.ui.main_loop() except KeyboardInterrupt: self.log.debug('Interceptado Keyboard Interrupt') self.ui.main_quit() def __clean(self): '''Limpieza de ficheros .pyc y .pyo''' self.log.debug("Limpiando la casa...") path = os.path.join(os.path.dirname(__file__)) i = 0 for root, dirs, files in os.walk(path): for f in files: path = os.path.join(root, f) if path.endswith('.pyc') or path.endswith('.pyo'): self.log.debug("Borrado %s" % path) os.remove(path) def __save_credentials(self): print "This assistant will allow you store your credentials" print "Available protocols" print "===================" for i in range(len(PROTOCOLS)): print "%d - %s" % (i, PROTOCOLS[i]) while 1: protocol = int(raw_input("Select protocol: ")) if protocol <= len(PROTOCOLS): break else: print "Invalid protocol, please try again" user, passwd, rem = self.get_remembered(protocol) if user != '' and passwd != '': delete = raw_input("Delete your current credentials (%s)? [Y/n/q]: " % user) if delete == '' or delete.lower() == 'y': self.remember(pro=protocol, rem=False) return elif delete.lower() == 'q': return user = raw_input("User: "******"Password: "******"Retype password: "******"Password mismatch, please try again" self.remember(user, passwd, protocol, True) print "Credentials saved successfully" def __validate_credentials(self, val): '''Chequeo de credenciales''' if val.type == 'error': self.ui.cancel_login(val.errmsg) elif val.type == 'profile': self.profile = val.items self.config = ConfigHandler(self.profile.username, self.current_protocol) self.config.initialize() if self.tmp_key is not None: self.config.write('Auth', 'oauth-key', self.tmp_key) if self.tmp_secret is not None: self.config.write('Auth', 'oauth-secret', self.tmp_secret) if self.tmp_verifier is not None: self.config.write('Auth', 'oauth-verifier', self.tmp_verifier) self.httpserv.update_img_dir(self.config.imgdir) self.httpserv.set_credentials(self.profile.username, self.profile.password, self.api.protocol.http) self.__signin_done() def __validate_token(self, val): if val.type == 'auth-done': token = val.items self.__save_oauth_token(token.key, token.secret, token.verifier) elif val.type == 'auth-token': self.ui.show_oauth_pin_request(val.items) def __save_oauth_token(self, key, secret, verifier): self.tmp_key = key self.tmp_secret = secret self.tmp_verifier = verifier auth = self.config.read_section('Auth') self.api.auth(self.tmp_username, self.tmp_passwd, auth, self.__validate_credentials) def __done_follow(self, response): user = response.items[1] follow = response.items[2] if response.type == 'error': msg = response.errmsg % user self.ui.following_error(msg, follow) elif response.type == 'mixed': self.profile = response.items[0] self.ui.update_user_profile(self.profile) self.ui.update_follow(user, follow) def __direct_done(self, status): self.ui.tweet_done(status) def __tweet_done(self, status): if status: self.profile.statuses_count += 1 self.ui.update_user_profile(self.profile) self.ui.tweet_done(status) def __signin_done(self): '''Inicio de sesion finalizado''' resp_profile = self.profile # TODO: Llenar con el resto de listas self.lists = { 'timeline': MicroBloggingList('timeline', '', _('Timeline'), _('tweet'), _('tweets')), 'replies': MicroBloggingList('replies', '', _('Replies'), _('mention'), _('mentions')), 'directs': MicroBloggingList('directs', '', _('Directs'), _('direct'), _('directs')), 'sent': MicroBloggingList('sent', '', _('My Tweets'), _('tweet'), _('tweets')), } if self.interface != 'cmd': plists = self.api.get_lists() for ls in plists: self.lists[str(ls.id)] = MicroBloggingList(str(ls.id), ls.user, ls.name, _('tweet'), _('tweets')) # Evita que la aplicación reviente si se borra una lista por fuera try: column1 = self.lists[self.config.read('Columns', 'column1')] except KeyError: self.log.debug('La lista %s no existe. Se carga el Timeline' % self.config.read('Columns', 'column1')) column1 = self.lists['timeline'] try: column2 = self.lists[self.config.read('Columns', 'column2')] except KeyError: self.log.debug('La lista %s no existe. Se carga el Timeline' % self.config.read('Columns', 'column2')) column2 = self.lists['timeline'] try: column3 = self.lists[self.config.read('Columns', 'column3')] except KeyError: self.log.debug('La lista %s no existe. Se carga el Timeline' % self.config.read('Columns', 'column3')) column3 = self.lists['timeline'] self.viewed_cols = [column1, column2, column3] self.api.protocol.muted_users = self.config.load_muted_list() self.api.protocol.filtered_terms = self.config.load_filtered_list() self.ui.set_lists(self.lists, self.viewed_cols) self.ui.show_main(self.config, self.global_cfg, resp_profile) if self.interface == 'cmd': return self._update_column1() if self.testmode: self._update_rate_limits() self._update_friends() return self._update_column2() self._update_column3() self._update_rate_limits() self._update_favorites() self._update_friends() def _update_column1(self): '''Actualizar columna 1''' self.ui.start_updating_column1() count = int(self.config.read('General', 'num-tweets')) column = self.viewed_cols[0] self.api.update_column(self.ui.update_column1, count, column) def _update_column2(self): '''Actualizar columna 2''' self.ui.start_updating_column2() count = int(self.config.read('General', 'num-tweets')) column = self.viewed_cols[1] self.api.update_column(self.ui.update_column2, count, column) def _update_column3(self): '''Actualizar columna 3''' self.ui.start_updating_column3() count = int(self.config.read('General', 'num-tweets')) column = self.viewed_cols[2] self.api.update_column(self.ui.update_column3, count, column) def _update_favorites(self): '''Actualizar favoritos''' self.api.update_favorites(self.ui.update_favorites) def _update_rate_limits(self): self.api.update_rate_limits(self.ui.update_rate_limits) def _update_friends(self): '''Actualizar amigos''' self.api.get_friends() def get_remembered(self, index): protocol = PROTOCOLS[index] us = self.protocol_cfg[protocol].read('Login', 'username') pw = self.protocol_cfg[protocol].read('Login', 'password') au = self.global_cfg.read('Startup', 'autologin') try: if au == 'on': auto = True else: auto = False if us != '' and pw != '': a = base64.b64decode(pw) b = a[1:-1] c = base64.b32decode(b) d = c[1:-1] e = base64.b16decode(d) pwd = e[0:len(us)]+ e[len(us):] return us, pwd, True, auto else: return us, pw, False, False except TypeError: self.protocol_cfg[protocol].write('Login', 'username','') self.protocol_cfg[protocol].write('Login', 'password','') self.global_cfg.write('Startup', 'autologin', 'off') return '', '', False, False def remember(self, us='', pw='', pro=0, rem=False, auto=False): protocol = PROTOCOLS[pro] if not rem: self.protocol_cfg[protocol].write('Login', 'username', '') self.protocol_cfg[protocol].write('Login', 'password', '') return a = base64.b16encode(pw) b = us[0] + a + ('%s' % us[-1]) c = base64.b32encode(b) d = ('%s' % us[-1]) + c + us[0] e = base64.b64encode(d) pwd = e[0:len(us)]+ e[len(us):] self.protocol_cfg[protocol].write('Login', 'username', us) self.protocol_cfg[protocol].write('Login', 'password', pwd) if auto: self.global_cfg.write('Startup', 'autologin', 'on') else: self.global_cfg.write('Startup', 'autologin', 'off') def signin(self, username, password, protocol): self.config = ConfigHandler(username, protocol) self.config.initialize_failsafe() auth = self.config.read_section('Auth') self.tmp_username = username self.tmp_passwd = password self.current_protocol = protocol self.api.start_oauth(auth, protocol, self.__validate_token) def auth_token(self, pin): print 'PIN', pin self.api.authorize_oauth_token(pin, self.__save_oauth_token) def signout(self): '''Finalizar sesion''' self.save_muted_list() self.save_filtered_list() self.log.debug('Desconectando') if self.httpserv and self.interface != 'cmd': self.httpserv.quit() self.httpserv.join(0) if self.api: self.api.quit() if self.interface != 'cmd': self.api.join(0) sys.exit(0) def update_status(self, text, reply_id=None): if text.startswith('D '): self.api.update_status(text, reply_id, self.__direct_done) else: self.api.update_status(text, reply_id, self.__tweet_done) def destroy_status(self, id): self.api.destroy_status(id, self.ui.after_destroy_status) def set_favorite(self, id): self.api.set_favorite(id, self.ui.tweet_changed) def unset_favorite(self, id): self.api.unset_favorite(id, self.ui.tweet_changed) def repeat(self, id): self.api.repeat(id, self.__tweet_done) def follow(self, user): self.api.follow(user, self.__done_follow) def unfollow(self, user): self.api.unfollow(user, self.__done_follow) def update_profile(self, new_name, new_url, new_bio, new_location): self.api.update_profile(new_name, new_url, new_bio, new_location, self.ui.update_user_profile) def in_reply_to(self, id): self.api.in_reply_to(id, self.ui.update_in_reply_to) def get_conversation(self, id): self.api.get_conversation(id, self.ui.update_conversation) def mute(self, users): self.api.mute(users, self.ui.tweet_changed) def filter_term(self, term): self.api.filter_term(term, self.ui.tweet_changed) def short_url(self, text, callback): service = self.config.read('Services', 'shorten-url') self.httpserv.short_url(service, text, callback) def expand_url(self, url, callback): self.httpserv.expand_url(url, callback) def download_user_pic(self, user, pic_url, callback): self.httpserv.download_pic(user, pic_url, callback) def upload_pic(self, path, message, callback): service = self.config.read('Services', 'upload-pic') self.httpserv.upload_pic(service, path, message, callback) def search(self, query): self.ui.start_search() self.api.search(query, self.ui.update_search) def get_popup_info(self, tweet_id, user): if self.api.is_marked_to_fav(tweet_id): return {'marking_fav': True} elif self.api.is_marked_to_unfav(tweet_id): return {'unmarking_fav': True} elif self.api.is_marked_to_del(tweet_id): return {'deleting': True} rtn = {} if self.api.friends_loaded(): rtn['friend'] = self.api.is_friend(user) rtn['fav'] = self.api.is_fav(tweet_id) return rtn def save_config(self, config, update): self.config.save(config) if update: self.ui.update_config(self.config) def save_global_config(self, config): self.global_cfg.save(config) def save_muted_list(self): if self.config: self.config.save_muted_list(self.api.protocol.muted_users) def get_muted_list(self): return self.api.get_muted_list() def save_filtered_list(self): if self.config: self.config.save_filtered_list(self.api.protocol.filtered_terms) def get_filtered_list(self): return self.api.get_filtered_list() def destroy_direct(self, id): self.api.destroy_direct(id, self.ui.after_destroy_direct) def get_friends(self): return self.api.get_single_friends_list() def get_hashtags_url(self): return self.api.protocol.tags_url def get_groups_url(self): return self.api.protocol.groups_url # FIXME: Debería pasarse como parámetro el protocolo def get_profiles_url(self): return self.api.protocol.profiles_url def get_viewed_columns(self): return self.viewed_cols def change_column(self, index, new_id): print 'change_column', self.lists.keys(), index, new_id if self.lists.has_key(new_id): self.viewed_cols[index] = self.lists[new_id] if index == 0: self.ui.home.timeline.clear() self._update_column1() elif index == 1: self.ui.home.replies.clear() self._update_column2() elif index == 2: self.ui.home.direct.clear() self._update_column3() else: self.ui.set_column_item(index, reset=True) self.log.debug('Error: la columna %s no existe' % new_id) def is_friend(self, user): return self.api.is_friend(user)