# File: nntpbox.py # Purpose: nntp news class import utils import gtk import timeoutsocket import pynenntp import string import socket import time import rfc822 import threading import cStringIO import cPickle from pyneheaders import * import msgfilter from superbox import * import boxformats from ptk.big_edit_box import * import ptk.personalitybox import pynei18n from boxtypes.net_exceptions import * from nntp_io import nntp_io import ptk.personalitybox import ptk.misc_widgets import ptk.progresswin import personality class newsgroup(superbox): """ A subscribed newsgroup. """ def get_flags(self): return BOX_ISDELETEABLE | BOX_MAKE_NEW_MSG | \ BOX_REPLY_SINGLE | BOX_REPLY_GROUP | BOX_REPLY_FORWARD | \ BOX_UPDATE_METHOD def __init__(self, user, uid, parent_nntpbox=None, name=None): self.load(user, uid, parent_nntpbox, name) def save(self, user): tosave = {} def _saveme(key, tosave=tosave, self=self): tosave[key] = self.__dict__[key] _saveme("uid") _saveme("name") _saveme("opts") _saveme("filters") _saveme("last_checked") _saveme("expire_after") _saveme("export_format") _saveme("collect_policy") _saveme("num_unread") f = open(self.uid+".fol", "w") cPickle.dump(ver_stamp, f, 1) cPickle.dump("NEWSGROUP", f, 1) cPickle.dump(user.parent_of(self).uid, f, 1) cPickle.dump(tosave, f, 1) f.close() def load(self, user, uid, parent_nntpbox=None, name=None): """ We only need parent_nntpbox and name the first time the newsgroup is created, not when we load it again. """ # Load/create newsgroup self.__dict__ = {} version = ver_stamp try: f = open(uid+".fol", "r") except IOError: # Creating new folder pass else: try: version = cPickle.load(f) type = cPickle.load(f) parent_uid = cPickle.load(f) self.__dict__ = cPickle.load(f) except Exception,e: print "Error loading box '"+uid+"': "+str(e) print "Restoring defaults..." f.close() parent_nntpbox = user.get_folder_by_uid(parent_uid) def _ifmissing(key, value, self=self): if not self.__dict__.has_key(key): self.__dict__[key] = value _ifmissing("uid", uid) _ifmissing("name", name) _ifmissing("opts", OPT_THREAD) _ifmissing("filters", []) if parent_nntpbox: _ifmissing("expire_after", parent_nntpbox.expire_after) # set last checked as 'expire_after' days ago t = time.gmtime( time.time() - 60*60*24 * parent_nntpbox.expire_after) yymmdd, hhmmss = nntp_io.gmtime_2_nntptime(t) # Last downloaded news. nntp format _ifmissing("last_checked", (yymmdd, hhmmss)) _ifmissing("export_format", (boxformats.BF_FLATFILEBOX, None)) _ifmissing("collect_policy", (SERVER_LEAVE, "")) _ifmissing("num_unread", 0) self.startup(user, parent_nntpbox) def startup(self, user, parent_nntpbox=None): """ Get an io module for loading/saving articles """ i = self.export_format[0] # this is a pretty piece of code :-) bf_class = boxformats.__dict__[boxformats.__all__[i]]. \ __dict__[boxformats.__all__[i]] if parent_nntpbox: uid_path = parent_nntpbox.uid+"/"+self.name else: uid_path = user.parent_of(self).uid+"/"+self.name self._io = bf_class(user, self, prefix=uid_path) self.messages = self._io.get_contents() def get_connection(self, parent_nntpbox, num_connections=1): # Returns a list if more than one connection desired. # Only the first will be 'active'. Get the rest alive # with con.[check_]renew_connection() if num_connections == 1: return [ nntp_io.get_connection(parent_nntpbox) ] else: servers = [] servers.append(nntp_io.get_connection(parent_nntpbox)) for i in range(1, num_connections): servers.append( nntp_io.get_connection(parent_nntpbox, no_connection=1) ) return servers def kill_thread(self, msg_id): """ Kill this message and all referencing it. """ # delete actual message self.delete_article(msg_id) # cache message headers msgs = [] for i in self.messages: m = self.load_header(i) if m != None: msgs.append(m) # nuke ones referencing this. for i in msgs: if i[HEAD_REFERENCES] == None: continue elif string.find(i[HEAD_REFERENCES], msg_id) != -1: self.delete_article(i[HEAD_MESSAGE_ID]) def get_rest_of_msg(self, user, msg_ids, progressbar): """ Collect the rest of a message whose header but not body has already been downloaded. """ # Mark the messages for collection for msg_id in msg_ids: msg = self.load_article(msg_id) msg.opts = msg.opts | MSG_ISMARKED self.save_article(msg) # Examines all headers. A bit slower... self.collect_bodies_of_marked(user, progressbar, []) ############################################################## def recv_get_pending(self, servers, logfunc): """ Return list of messages to be collected. Returns None on error. """ # Get nice nntp format last check times yymmdd, hhmmss = self.last_checked while 1: new_time = servers[0].get_server_time() if new_time == None: # connection timeout. get new one try: servers[0].renew_connection() except connect_exception, e: logfunc(_("Error")+": "+str_net_error(e)) #progressbar.set_percentage(0.0) #progressbar.set_format_string(usermsg) return continue else: break self.last_checked = (new_time[1], new_time[2]) # Get list of new articles ids logfunc(_("Collecting %s headers...") % self.name) #try: # a_list = servers[0].newnews(self.name, yymmdd, hhmmss)[1] #except pynenntp.error_perm, e: # Disabled newnews use for the moment, since it tends to be # a POS (on both my ISPs anyway...) try: # newnews not available? use group() and xhdr() try: a_list = servers[0].group(self.name) except pynenntp.NNTPError, e: logfunc(_("Error")+": %s" % str_net_error(e)) return # start and message numbers s_msgs = a_list[2] e_msgs = a_list[3] total = int (e_msgs) - int (s_msgs) def _on_msgid_hdr_get (num): num = num/2 if total: logfunc(_("Got %d %s headers") % (num, self.name), log=0, pos=num/float(total)) else: logfunc(_("Got %d %s headers") % (num, self.name), log=0, pos=1.0) # get message ids. msg_ids = {} for i in servers[0].xhdr("message-id", s_msgs+"-"+e_msgs, _on_msgid_hdr_get)[1]: msg_ids[i[0]] = i[1] total = len (msg_ids) def _on_date_hdr_get (num): num = total/2+num/2 if total == 0: _pos = 0.0 else: _pos=num/float(total) logfunc(_("Got %d %s headers") % (num, self.name), log=0, pos=_pos) # get date headers try: _a_list = [] for i in servers[0].xhdr("date", s_msgs+"-"+e_msgs, _on_date_hdr_get)[1]: id = i[0] try: date = rfc822.parsedate(i[1]) except IndexError: # eek. just get it _a_list.append( msg_ids[id] ) continue if date == None: # failed to parse.. just assume _a_list.append( msg_ids[id] ) continue elif date[0] < 1000: # 2 digit years... year = 2000 + date[0] date = (year,) + date[1:] # add one to day... date = date[0:2] + ( date[2]+1, ) + date[3:] if (yymmdd, hhmmss) < nntp_io.gmtime_2_nntptime(date): # more recent than last checked _a_list.append( msg_ids[id] ) except pynenntp.error_perm: # this server doesn't support jack shit. just # collect all available messages we don't have # and to hell with proper expiry, etc. :-( _a_list = [] for i in msg_ids.keys(): _a_list.append( msg_ids[i] ) # eliminate messages we already have a_list = [] for i in _a_list: if not (i in self.messages): a_list.append(i) del _a_list del msg_ids except timeout_exception, e: # probably "411 no such group" logfunc(_("Error")+": %s" % str_net_error(e)) return logfunc(_("%d new articles on %s") % (len(a_list), self.name)) return a_list def update(self, user, progressbar, servers=[]): """ Download new articles. """ self.locked = 1 final = 0 parent_nntpbox = user.parent_of(self) usermsg = self.name+": "+_("Connecting to %s...") % parent_nntpbox.server if servers == []: # We will be the only thing using the progressbar final = 1 progressbar.log_msg(usermsg) progressbar.bar_msg(usermsg) def logfunc(msg, progressbar=progressbar, log=1, pos=None): if pos: if pos < 0.0: pos = 0.0 elif pos > 1.0: pos = 1.0 progressbar.bar_pos(pos) if log: progressbar.log_msg(msg) progressbar.bar_msg(msg) num_threads = parent_nntpbox.collection_threads if len(servers) == 0: try: for con in self.get_connection(parent_nntpbox, num_connections=num_threads): servers.append(con) except connect_exception, e: usermsg = _("Error connecting to %s: %s") % (self.name, str_net_error(e)) progressbar.log_msg(usermsg) progressbar.bar_pos(0.0) progressbar.bar_msg(usermsg) if final: progressbar.bar_enable(False) progressbar.finished() del self.locked return # download marked headers if desired if self.opts & OPT_HEADERS_ONLY: self.collect_bodies_of_marked(user, progressbar, servers) # restore this or we fail later trying to remove it self.locked = 1 progressbar.bar_enable(True) # Get list of pending messages articles = self.recv_get_pending(servers, logfunc) # timeout or some other error in recv_get_pending if articles == None: progressbar.finished () del self.locked return start_num = len(articles) def incfunc(self=self, progressbar=progressbar, start_num=start_num, articles=articles): """ Update progress bar. """ num_left = len(articles) progressbar.bar_pos((start_num-num_left)/float(start_num)) progressbar.bar_msg("%d/%d of " % ((start_num-num_left), start_num) + self.name) # nothing to collect :-/ if len(articles) == 0: progressbar.bar_pos(0.0) progressbar.bar_msg("0/0 of " + self.name) if final: progressbar.bar_enable(False) progressbar.finished() del self.locked return # start collection threads incfunc() self.recv_collect_threaded(user, servers, msgfilter.filter_collect, logfunc, incfunc, articles) self.changed = 1 progressbar.bar_pos(0.0) if final: progressbar.bar_enable(False) progressbar.finished() # Update folder/message views user.queue_action(ACT_UPDATE) del self.locked def get_menu(self): """ This box type specific options. """ if self.opts & OPT_HEADERS_ONLY: return [ _("Download Marked") ] else: return [] def menu_chosen(self, _a, choice_n_user): """ Activate the chosen menu option. """ choice, user = choice_n_user if (choice == _("Download Marked")) and (not self.__dict__.has_key("locked")): pager = ptk.progresswin.ProgressWin(_("Collecting messages..."), user, hidetext=_("Show Logs")) progressbar = pager.get_progress_bar() threading.Thread(target=self.collect_bodies_of_marked, args=(user, progressbar)).start() return def collect_bodies_of_marked(self, user, progressbar, servers=[]): """ Download bodies of marked messages (those with only headers downloaded) """ parent_nntpbox = user.parent_of(self) self.locked = 1 final = 0 def logfunc(msg, progressbar=progressbar): progressbar.log_msg(msg) progressbar.bar_msg(msg) usermsg = _("Searching for marked messages in %s...") % self.name if servers == []: # we are the last guy using this progressbar final = 1 progressbar.bar_pos(0.0) progressbar.bar_msg(usermsg) progressbar.log_msg(usermsg) no_bdy_msgs = [] for i in self.messages: head = self.load_header(i) if (head[HEAD_OPTS] & MSG_NO_BODY) and (head[HEAD_OPTS] & MSG_ISMARKED): msg = self.load_article(i) no_bdy_msgs.append(msg) if len(no_bdy_msgs) == 0: usermsg = _("No marked messages to collect") progressbar.log_msg(usermsg) progressbar.bar_msg(usermsg) if final == 1: progressbar.bar_enable(False) del self.locked return usermsg = _("%d marked messages to collect in %s") % (len(no_bdy_msgs), self.name) progressbar.log_msg(usermsg) progressbar.bar_msg(usermsg) num_threads = parent_nntpbox.collection_threads if len(servers) == 0: try: for con in self.get_connection(parent_nntpbox, num_connections=num_threads): servers.append(con) except connect_exception, e: usermsg = _("Error connecting to %s: %s") % (self.name, str_net_error(e)) progressbar.log_msg(usermsg) if final: progressbar.bar_enable(False) progressbar.bar_pos(0.0) progressbar.bar_msg(usermsg) del self.locked return start_num = len(no_bdy_msgs) def incfunc(self=self, progressbar=progressbar, start_num=start_num, no_bdy_msgs=no_bdy_msgs): """ Update progress bar. """ num_left = len(no_bdy_msgs) progressbar.bar_pos((start_num-num_left)/float(start_num)) progressbar.bar_msg("%d/%d marked of " % ((start_num-num_left), start_num) + self.name) # no marked messages to collect if len(no_bdy_msgs) == 0: if final: progressbar.bar_enable(False) progressbar.bar_pos(0.0) del self.locked return # collection function def recvfunc(user, self, con, msg): try: msg.body = msg.body + con.get_body(msg.headers["message-id"]) except recv_exception: # message is probably no longer on the server return "" else: msg.opts = msg.opts & (~MSG_NO_BODY) msg.opts = msg.opts & (~MSG_ISMARKED) msg.parseheaders(user) self.save_article(msg) return "" # Start collection threads incfunc() self.recv_collect_threaded(user, servers, recvfunc, logfunc, incfunc, no_bdy_msgs) progressbar.bar_enable(False) if final: progressbar.bar_pos(0.0) self.changed = 1 user.queue_action(ACT_UPDATE) def getstats(self): """ Returns a tuple. (total msgs, ). """ return (str (self.num_unread) + " ("+ str(len(self.messages)) + ")",) def setup(self, user, parent_win): """ Configure a newsgroup's collection settings. """ win = gtk.Window() win.set_title(_("%s Setup") % self.name) win.set_transient_for(parent_win) box = gtk.VBox() win.add(box) box.show() notebook = gtk.Notebook() notebook.set_tab_pos(gtk.POS_TOP) box.pack_start(notebook) notebook.show() # First page: Misc settingsi box0 = gtk.VBox() box0.set_border_width(5) label = gtk.Label(_("Settings")) notebook.append_page(box0, label) box0.show() box1 = gtk.HBox() box0.pack_start(box1) box1.show() box1_1 = gtk.VBox(spacing=5) box1_1.set_border_width(5) box1.pack_start(box1_1) box1_1.show() box1_2 = gtk.VBox(spacing=5) box1_2.set_border_width(5) box1.pack_end(box1_2) box1_2.show() input_boxes = ( ( _("Last Checked (YYMMDD):"), self.last_checked[0] ), ( _("Last Checked (HHMMSS):"), self.last_checked[1] ), ( _("Expire after (days):"), str(self.expire_after) ) ) entry_boxes = [] for x in range(0, len(input_boxes)): label = gtk.Label(input_boxes[x][0]) label.set_justify(gtk.JUSTIFY_LEFT) box1_1.pack_start(label) label.show() entry_box = gtk.Entry() entry_box.set_text(input_boxes[x][1]) box1_2.pack_start(entry_box) entry_box.show() entry_boxes.append(entry_box) settings_box0 = big_edit_box( self, ( ("opts", _("Only collect headers"), VAR_TYPE_PACKED_BIT_BOOLEAN, 0, OPT_HEADERS_ONLY), ("opts", _("Thread messages"), VAR_TYPE_PACKED_BIT_BOOLEAN, 0, OPT_THREAD) ) ) box0.pack_start(settings_box0, expand=False) settings_box0.show() # 2nd page: Filters label = gtk.Label(_("Filters")) filterbox = msgfilter.filters_editlist(self, user) notebook.append_page(filterbox, label) filterbox.show() def save_changes(_button, boxes=entry_boxes, self=self, user=user, \ settings_box0=settings_box0, filterbox=filterbox, win=win): # Extract info self.last_checked = (boxes[0].get_text(), boxes[1].get_text()) filterbox.apply_changes() settings_box0.apply_changes() try: self.expire_after = int(boxes[2].get_text()) except ValueError: self.expire_after = None # save changes to disk self.save(user) # update folder list self.changed = 1 user.update() def save_changes_close(_button, win=win, save_changes=save_changes): save_changes(_button) win.destroy() def _cancel(_button, win=win): win.destroy() # Seperator between entry boxes and buttons separator = gtk.HSeparator() box.pack_start(separator, expand=False) separator.show() # Buttons at bottom buttonbox = ptk.misc_widgets.MyButtonBox() box.pack_start(buttonbox, expand=False) buttonbox.show() button = gtk.Button(stock="gtk-ok") button.connect("clicked", save_changes_close) buttonbox.pack_end(button, expand=False) button.show() button = gtk.Button(stock="gtk-apply") button.connect("clicked", save_changes) buttonbox.pack_end(button, expand=False) button.show() button = gtk.Button(stock="gtk-cancel") button.connect("clicked", _cancel) buttonbox.pack_end(button, expand=False) button.show() win.show() class nntpbox(superbox): """ News box. """ def get_flags(self): return BOX_ISDELETEABLE | BOX_UPDATE_METHOD def __init__(self, user, uid): self.load(user, uid) def save(self, user): tosave = {} def _saveme(key, tosave=tosave, self=self): tosave[key] = self.__dict__[key] _saveme("uid") _saveme("name") _saveme("opts") _saveme("server") _saveme("port") _saveme("username") _saveme("password") _saveme("expire_after") _saveme("collection_threads") _saveme("personalities") _saveme("default_personality") _saveme("groups") _saveme("groups_last_checked") f = open(self.uid+".fol", "w") cPickle.dump(ver_stamp, f, 1) cPickle.dump("NNTPBOX", f, 1) cPickle.dump(tosave, f, 1) f.close() def load(self, user, uid): self.load_box (user, uid) def _ifmissing(key, value, self=self): if not self.__dict__.has_key(key): self.__dict__[key] = value _ifmissing("uid", uid) _ifmissing("name", _("News")) _ifmissing("opts", 0) _ifmissing("server", "news.someisp.com") _ifmissing("port", 119) _ifmissing("username", "") _ifmissing("password", "") _ifmissing("expire_after", 7) _ifmissing("collection_threads", 4) # Keys in user.personalities dict _ifmissing("personalities", []) self.contents = [] if not self.__dict__.has_key("default_personality"): # Add a default personality p = personality.personality(self.name+" default") p.uid = user.get_personality_uid() user.personalities[p.uid] = p self.personalities.append(p.uid) self.default_personality = p.uid # List of newsgroups in form returned by server _ifmissing("groups", []) # Last updated group list _ifmissing("groups_last_checked", None) def sort_groups(self): def _sort(name1, name2): #name1 = a[0] #name2 = b[0] if name1 < name2: return -1 elif name1 > name2: return 1 return 0 self.groups.sort(_sort) def get_menu(self): """ This box type specific options. """ return [] def menu_chosen(self, _a, choice): """ Activate the chosen menu option. """ return def getstats(self): """ Returns a tuple. (subscribed groups). """ return (len(self.contents),) def get_connection(self): """ Connect to the news server. Return an NNTP object. """ return nntp_io.get_connection(self) def get_new_group_list(self, progressbar): """ Get a new list of newsgroups. Can [will] take ages. this should be threaded or something... """ usermsg = self.name+": "+_("Connecting to %s...") % self.server progressbar.log_msg(usermsg) progressbar.bar_msg(usermsg) try: ns = nntp_io.get_connection(self) except connect_exception, e: usermsg = _("Error connecting to %s: %s") % (self.name, str_net_error(e)) progressbar.log_msg(usermsg) progressbar.bar_msg(usermsg) progressbar.bar_enable(False) progressbar.finished() return date = ns.get_server_time() self.groups_last_checked = (date[1], date[2]) def _on_progress (num): progressbar.bar_msg (_("%d groups downloaded...") % num) _on_progress (0) crudelist = ns.list(_on_progress)[1] self.groups = [] progressbar.finished () for x in crudelist: self.groups.append("%s %s" % (x[0], x[3])) ns.close() # sort group list self.sort_groups() return def subscribe_to(self, groupname, user): """ Subscribe to a group """ def sort_groups(a, b): if a.name < b.name: return -1 elif a.name > b.name: return 1 else: return 0 # Check it isn't already subscribed to for x in self.contents: if x.name == groupname: break ng = newsgroup(user, user.get_uid("ng"), parent_nntpbox=self, name=groupname) self.contents.append(ng) self.contents.sort(sort_groups) ng.startup(user) def setup(self, user, parent_win): """ Configure an nntp box. """ win = gtk.Window() win.set_title(self.name+" "+_("Setup")) win.set_transient_for(parent_win) box = gtk.VBox() win.add(box) box.show() notebook = gtk.Notebook() notebook.set_tab_pos(gtk.POS_TOP) box.pack_start(notebook) notebook.show() # First page: Misc settings settings_box = big_edit_box(self, ( ("name", _("Name:"), VAR_TYPE_STRING, 0, 0), ("server", _("Server:"), VAR_TYPE_STRING, 0, 0), ("port", _("Port:"), VAR_TYPE_INTEGER, 0, 119), ("username", _("Username:"), VAR_TYPE_STRING, 0, 0), ("password", _("Password:"), VAR_TYPE_STRING, MOD_HIDE, 0), ("expire_after", _("Default expiry (days):"), VAR_TYPE_INTEGER, 0, None), ("collection_threads", _("Download threads:"), VAR_TYPE_INTEGER, 0, 4) ) ) label = gtk.Label(_("Settings")) notebook.append_page(settings_box, label) settings_box.show() # Seperator between entry boxes and buttons separator = gtk.HSeparator() box.pack_start(separator, expand=False) separator.show() # 2nd page: personalities label = gtk.Label(_("Personalities")) personbox = ptk.personalitybox.personalitybox(self, user, win) notebook.append_page(personbox, label) personbox.show() # 3rd page: Newsgroup settings box2 = gtk.HBox() box2.set_border_width(10) label = gtk.Label(_("Newsgroups")) notebook.append_page(box2, label) box2.show() box2_1 = gtk.VBox(spacing=5) box2_1.set_border_width(5) box2.pack_start(box2_1) box2_1.show() grouplistbox = gtk.CList(2, [ _("Available groups"), _("Posting") ] ) grouplistbox.set_column_width(0,150) grouplistbox.set_column_width(1,20) swin = gtk.ScrolledWindow() swin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) box2_1.pack_end(swin) swin.show() swin.add(grouplistbox) grouplistbox.show() searchbox = gtk.Entry() box2_1.pack_start(searchbox, expand=False) searchbox.show() def _search(_button, self=self, glist=grouplistbox, sbox=searchbox): search = sbox.get_text() # Nothing. Unfiltered if search == "": glist.freeze() # Wipe NG list glist.clear() # add NGs for x in self.groups: glist.append(string.split(x)) glist.thaw() return # Otherwise do some filtering fgroups = [] for x in self.groups: name, mode = string.split(x) if string.find(name, search) != -1: fgroups.append((name, mode)) glist.freeze() # Wipe NG list glist.clear() # add filtered NGs for x in fgroups: glist.append(x) glist.thaw() def _key_press(w, event, _search=_search): if event.string == '\r': _search(w) # We want to search if return is hit searchbox.connect("key_press_event", _key_press) box2_2 = gtk.VBox(spacing=5) box2_2.set_border_width(5) box2.pack_end(box2_2, expand=False) box2_2.show() search_button = gtk.Button(" "+_("Search")+" ") search_button.connect("clicked", _search) box2_2.pack_start(search_button, expand=False) search_button.show() # add NGs grouplistbox.freeze() for x in self.groups: grouplistbox.append(string.split(x)) grouplistbox.thaw() def _subscribe_group(_button, self=self, user=user, \ searchbox=searchbox, glist=grouplistbox): import mainwin # Nothing selected if glist.selection == []: # nothing selected. try subscribing to what is # in the search box if searchbox.get_text() != "": self.subscribe_to(searchbox.get_text(), user) else: return else: selected = glist.selection[0] self.subscribe_to(glist.get_text(selected, 0), user) # Big folderview update self.changed = 1 user.update(mainwin.UPDATE_ALL) newlist_button = gtk.Button(" "+_("New List")+" ") box2_2.pack_end(newlist_button, expand=False) newlist_button.show() def _get_new_group_list(_button, newlist_button=newlist_button, settings_box=settings_box, self=self, glist=grouplistbox): pager = ptk.progresswin.ProgressWin(_("Getting %s group list...") % self.name, user, hidetext=_("Show logs"), parent_win=parent_win) progressbar = pager.get_progress_bar () stage = [0] # make current changes active briefly... # XXX it sucks indexing entry_objects like this... a # dictionary would be nicer oldname = self.name self.name = settings_box.entry_objects[0].get_text() oldserver = self.server self.server = settings_box.entry_objects[1].get_text() try: oldport = self.port self.port = int(settings_box.entry_objects[2].get_text()) except ValueError: self.port = 119 oldusername = self.username self.username = settings_box.entry_objects[3].get_text() oldpassword = self.password self.password = settings_box.entry_objects[4].get_text() # A callback function to do UI updates, # so we don't have to use threads_enter/leave def _new_gl_timeout_func (user): if stage[0] == 0: return if stage[0] == 1: newlist_button.set_sensitive(False) stage[0] = 0 return if stage[0] == 2: newlist_button.set_sensitive(True) glist.freeze() # Wipe NG list glist.clear() # add NGs for x in self.groups: glist.append(string.split(x)) glist.thaw() stage[0] = 0 user.timeout_remove (_new_gl_timeout_func) def _new_gl(progressbar, settings_box=settings_box, newlist_button=newlist_button, self=self, glist=glist): # get list of groups stage[0] = 1 self.get_new_group_list(progressbar) stage[0] = 2 # and restore settings self.name = oldname self.server = oldserver self.port = oldport self.username = oldusername self.password = oldpassword user.timeout_add (_new_gl_timeout_func) threading.Thread(target=_new_gl, args=(progressbar,)).start() newlist_button.connect("clicked", _get_new_group_list) subscribe_button = gtk.Button(" "+_("Subscribe")+" ") subscribe_button.connect("clicked", _subscribe_group) box2_2.pack_end(subscribe_button, expand=False) subscribe_button.show() def save_changes(_button, settings_box=settings_box, self=self, \ user=user, win=win, personbox=personbox): # Extract info settings_box.apply_changes() personbox.apply_changes() # save changes to disk self.save(user) # update folder list self.changed = 1 user.update() def save_changes_close(_button, win=win, save_changes=save_changes): save_changes(_button) win.destroy() def _cancel(_button, win=win): win.destroy() # Buttons at bottom buttonbox = ptk.misc_widgets.MyButtonBox() box.pack_start(buttonbox, expand=False) buttonbox.show() button = gtk.Button(stock="gtk-ok") button.connect("clicked", save_changes_close) buttonbox.pack_end(button, expand=False) button.show() button = gtk.Button(stock="gtk-apply") button.connect("clicked", save_changes) buttonbox.pack_end(button, expand=False) button.show() button = gtk.Button(stock="gtk-cancel") button.connect("clicked", _cancel) buttonbox.pack_end(button, expand=False) button.show() win.show() def update(self, user, progressbar): """ Download new news. """ usermsg = self.name+": "+_("Connecting to %s...") % self.server progressbar.log_msg(usermsg) progressbar.bar_msg(usermsg) try: # list of nntp connections, mostly null at the moment ns = [ nntp_io.get_connection(self) ] for i in range(1, self.collection_threads): ns.append( nntp_io.get_connection(self, no_connection=1) ) except connect_exception, e: usermsg = _("Error connecting to %s: %s") % (self.name, str_net_error(e)) progressbar.log_msg(usermsg) progressbar.bar_msg(usermsg) progressbar.bar_enable(False) progressbar.finished() return # newgroup list progress callback def _on_group_get (num): progressbar.bar_msg (_("%d groups downloaded...") % num) if self.groups_last_checked == None: usermsg = _("Getting %s newsgroup list...") % self.name progressbar.log_msg(usermsg) progressbar.bar_msg(usermsg) date = ns[0].get_server_time() self.groups_last_checked = (date[1], date[2]) crudelist = ns[0].list(_on_group_get)[1] self.groups = [] for x in crudelist: self.groups.append("%s %s" % (x[0], x[3])) usermsg = _("%s: %d newsgroups found.") % (self.name, len (crudelist)) progressbar.log_msg(usermsg) progressbar.bar_msg(usermsg) # sort group list self.sort_groups() self.save(user) usermsg = _("Checking %s for new newsgroups...") % self.name progressbar.log_msg(usermsg) progressbar.bar_msg(usermsg) # Convert time last checked to something nntp likes yymmdd, hhmmss = self.groups_last_checked # update last checked date = ns[0].get_server_time() self.groups_last_checked = (date[1], date[2]) # look for new groups try: _newgroups = ns[0].newgroups(yymmdd, hhmmss, _on_group_get)[1] # Convert to a nice list of group names and append to old list newgroups = [] for x in _newgroups: newgroups.append ("%s %s" % (x[0], x[3])) self.groups = self.groups + newgroups usermsg = _("%s: %d new newsgroups.") % (self.name, len(newgroups)) progressbar.log_msg(usermsg) progressbar.bar_msg(usermsg) if len(newgroups) != 0: # sort group list if there are new groups self.sort_groups() self.save(user) # erk. that didn't work... except (timeout_exception, pynenntp.error_temp), e: usermsg = _("Error %s getting %s newsgroup list...") % (str_net_error(e), self.name) progressbar.log_msg(usermsg) progressbar.bar_msg(usermsg) for x in self.contents: if not x.__dict__.has_key("locked"): x.update(user, progressbar=progressbar, servers=ns) usermsg = "Finished checking %s news" % self.name # update display progressbar.bar_pos(0.0) progressbar.bar_msg(usermsg) progressbar.bar_enable(False) progressbar.finished() self.changed = 1 user.queue_action(ACT_UPDATE)