def view(self): try: if self.inp: if len(self.inp) > 1: raise util.DeadMan('only 1 argument allowed') fp = open(self.inp[0], 'rb') else: fp = sys.stdin msg = email.message_from_file(fp) if self.inp: fp.close() except email.Errors.MessageParseError, inst: raise util.DeadMan(inst)
def __init__(self, ui, items=None, name='item', fmt='sf', ckey='', qfunc='quit', crit='pattern'): self.ui = ui self.items = items or [] # (text) items to choose from self.name = name # general name of an item self.fmt = fmt if self.fmt not in ('sf', 'bf'): raise util.DeadMan('%s: invalid format, use one of "sf", "bf"' % self.fmt) self.ckey = ckey # key to customize pager if self.ckey in ('q', 'Q', '-'): raise util.DeadMan("the `%s' key is internally reserved." % self.ckey) self.qfunc = qfunc # name of exit function self.crit = crit # name of criterion for customizing
def resolveopts(self, options): '''Adapts option sets. Sets protocol to "web", if "getdir" is without corresponding protocol scheme. Sets protocol to "mid", if it encounters one of messageopts. And, finally, update ui's attributes with current options.''' webschemes = ('web', 'http', 'ftp') messageopts = ('midrelax', 'news', 'local', 'browse', 'kiosk', 'mhiers', 'specdirs', 'mask') if options.get('getdir', '') and options['proto'] not in webschemes: options['proto'] = 'web' if options['proto'] != 'mid': for o in messageopts: val = options[o] if (val or val is not None and (o == 'mhiers' or o == 'specdirs')): options['proto'] = 'mid' options['decl'] = not options['midrelax'] break else: options['decl'] = True del options['midrelax'] try: for o in options.iterkeys(): setattr(self, o, options[o]) except KeyError: raise util.DeadMan('%s: invalid option' % o)
def updateconfig(self): if self.updated: return try: self.config.read(self.rcpath) except ConfigParser.ParsingError, inst: raise util.DeadMan(inst)
def filedeconstructor(self, fn): '''Checks if given file object is message or mailbox. If no, returns text contents of file or empty string if file is binary. Parses message/mailbox for relevant headers adding urls to list of items and returns text parts for further searching.''' # binary check from mercurial.util fp = open(fn, 'rb') try: text = fp.read() if '\0' in text: return '' elif self.ui.text: return text msg = _msgfactory(fp) if not msg: return text # else it's a message or a mailbox if not msg['message-id']: hint = ('make sure input is a raw message' ' - in mutt: unset pipe_decode -,' ' or use -t/--text to disable message detection') raise util.DeadMan('no message-id found', hint=hint) if not msg.get_unixfrom(): textlist = self.msgharvest(msg) else: # treat text like a mailbox because it might be one textlist = [] # list of strings to search mbox = mailbox.PortableUnixMailbox(fp, _msgfactory) while msg is not None: msg = mbox.next() if msg: textlist += self.msgharvest(msg) finally: fp.close() return '\n'.join(textlist)
def sign(self): self.sdir = util.absolutepath(self.sdir) sl = [f for f in os.listdir(self.sdir) if f.endswith(self.tail)] if not sl: raise util.DeadMan('no signature files in %s' % self.sdir) self.sigs = [sig for sig in map(self.getstring, sl) if sig] weed_re = None while True: reply = self.getsig(weed_re) if reply.startswith(self.ckey): weed_re = self.checkpattern(reply[1:]) else: break if self.items is not None: if self.items: sig = self.sep + self.items[0] else: self.sig = util.absolutepath(self.sig) fp = open(self.sig) try: sig = self.sep + fp.read() finally: fp.close() if not self.dest: self.ui.write(sig) else: for fn in self.dest: fp = open(fn, 'a') try: fp.write(sig) finally: fp.close() elif self.dest: self.ui.write('\n')
def configint(self, section, name, default=0): cfg = self.configitem(section, name) if cfg is None: return default try: return int(cfg) except ValueError, inst: raise util.DeadMan(inst)
def ivisit(self): try: fd = inotifyx.init() wd = inotifyx.add_watch(fd, self.items[0], inotifyx.IN_CLOSE) self.urlvisit() inotifyx.get_events(fd, self.keep) inotifyx.rm_watch(fd, wd) os.close(fd) except IOError: hint = ('consider increasing ' '/proc/sys/fs/inotify/max_user_watches') raise util.DeadMan('failed to enable inotify', hint=hint)
def kiosktest(self): '''Provides the path to an mbox file to store retrieved messages.''' if not self.ui.kiosk: self.ui.kiosk = tempfile.mkstemp(prefix='kiosk.')[1] return self.ui.kiosk = util.absolutepath(self.ui.kiosk) if (not os.path.exists(self.ui.kiosk) or not os.path.getsize(self.ui.kiosk)): # non existant or empty is fine return if not os.path.isfile(self.ui.kiosk): raise util.DeadMan('%s: not a regular file' % self.ui.kiosk) fp = open(self.ui.kiosk, 'rb') try: testline = fp.readline() finally: fp.close() try: p = email.Parser.Parser() check = p.parsestr(testline, headersonly=True) except email.Errors.HeaderParseError, inst: raise util.DeadMan(inst)
def download(self, urls): self.ui.getdir = util.savedir(self.ui.getdir) for url in map(urlregex.webschemecomplete, urls): bn = url.rstrip('/').split('/')[-1] path = os.path.join(self.ui.getdir, bn) self.ui.note('downloading to %s ...\n' % path) s = self.request(url) if s: try: fp = open(path, 'wb') fp.write(s) fp.close() except IOError, inst: raise util.DeadMan(inst)
def formwrap(self): '''Checks excluding regexes and passes data to iterator.''' for i in self.defwidth, self.tabwidth: if not isinstance(i, int): raise util.DeadMan('integer expected, got "%s"' % i) try: if self.inp is None: lit = sys.stdin else: lit = iter(self.inp.splitlines(True)) self.literator(lit) except AttributeError: # list of files for f in self.inp: lit = open(f, 'rb') try: self.literator(lit) finally: lit.close()
def request(self, req, func='r'): result = None try: fp = self.opener.open(req) if func == 'r': result = fp.read() elif func == 'g': result = fp.geturl() elif func == 'i': result = fp.info() else: raise util.DeadMan('%s: invalid request instruction') fp.close() except urllib2.URLError, inst: if util.safehasattr(inst, 'reason'): self.ui.warn('failed to reach a server for %s\n' % req, 'reason: %s\n' % inst) else: self.ui.warn('server failure for %s\n' % req, 'error code: %s\n' % inst)
class kiosk(object): ''' Provides methods to search for and retrieve messages via their Message-ID. ''' mspool = '' # path to local mail spool msgs = [] # list of retrieved message objects muttone = True # configure mutt for display of 1 msg only mdmask = '^(cur|new|tmp)$' def __init__(self, ui, items=None): self.ui = ui self.items = items or [] def kiosktest(self): '''Provides the path to an mbox file to store retrieved messages.''' if not self.ui.kiosk: self.ui.kiosk = tempfile.mkstemp(prefix='kiosk.')[1] return self.ui.kiosk = util.absolutepath(self.ui.kiosk) if (not os.path.exists(self.ui.kiosk) or not os.path.getsize(self.ui.kiosk)): # non existant or empty is fine return if not os.path.isfile(self.ui.kiosk): raise util.DeadMan('%s: not a regular file' % self.ui.kiosk) fp = open(self.ui.kiosk, 'rb') try: testline = fp.readline() finally: fp.close() try: p = email.Parser.Parser() check = p.parsestr(testline, headersonly=True) except email.Errors.HeaderParseError, inst: raise util.DeadMan(inst) if check.get_unixfrom(): self.muttone = False else: raise util.DeadMan('%s: not a unix mailbox' % self.ui.kiosk)
def urlobject(self, search=True): '''Creates customized regex objects of url.''' kill_re = None if self.ui.proto not in valid_protos: raise util.DeadMan(self.ui.proto, ': invalid protocol parameter, use one of:\n', ', '.join(valid_protos)) if self.ui.proto == 'mailto': # be pragmatic and list not only declared self.url_re = _get_mailre() elif self.ui.proto != 'mid': self.url_re = re.compile(self.getraw(search), re.IGNORECASE | re.VERBOSE) if search: kill_re = re.compile(r'^url:\s?|\s+', re.IGNORECASE) elif self.ui.decl: self.url_re = re.compile(_declmidpat(), re.IGNORECASE | re.VERBOSE) if search: kill_re = re.compile(_nntppat(), re.IGNORECASE | re.VERBOSE) else: self.url_re = re.compile(r'(\b%s\b)' % _midpat(), re.IGNORECASE | re.VERBOSE) return kill_re
def urlcollect(self): '''Harvests urls from stdin or files.''' if not self.files: # stdin tempname = tempfile.mkstemp(prefix='urlcollector.')[1] fp = open(tempname, 'wb') try: fp.write(sys.stdin.read()) finally: fp.close() text = self.filedeconstructor(tempname) os.unlink(tempname) else: textlist = [] for fn in self.files: textlist.append(self.filedeconstructor(util.absolutepath(fn))) text = '\n'.join(textlist) if text: self.findurls(text) if self.ui.pat and self.items: try: ui_re = re.compile(r'%s' % self.ui.pat, re.IGNORECASE) except re.error, err: raise util.DeadMan("%s in pattern `%s'" % (err, self.ui.pat)) self.items = [i for i in self.items if ui_re.search(i)]
class viewhtml(pybrowser.browser): def __init__(self, safe, keep, app, args): self.ui = ui.ui() self.ui.updateconfig() pybrowser.browser.__init__(self, parentui=self.ui, app=app, evalurl=True) self.inp = args self.safe = safe or self.ui.configbool('html', 'safe') self.keep = keep if self.keep is None: self.keep = self.ui.configint('html', 'keep', 3) def cleanup(self, tmpdir): if self.keep: shutil.rmtree(tmpdir) def ivisit(self): try: fd = inotifyx.init() wd = inotifyx.add_watch(fd, self.items[0], inotifyx.IN_CLOSE) self.urlvisit() inotifyx.get_events(fd, self.keep) inotifyx.rm_watch(fd, wd) os.close(fd) except IOError: hint = ('consider increasing ' '/proc/sys/fs/inotify/max_user_watches') raise util.DeadMan('failed to enable inotify', hint=hint) def view(self): try: if self.inp: if len(self.inp) > 1: raise util.DeadMan('only 1 argument allowed') fp = open(self.inp[0], 'rb') else: fp = sys.stdin msg = email.message_from_file(fp) if self.inp: fp.close() except email.Errors.MessageParseError, inst: raise util.DeadMan(inst) if not msg: raise util.DeadMan('input not a message') if not msg['message-id']: hint = ('make sure input is a raw message,' ' in mutt: unset pipe_decode') raise util.DeadMan('no message-id found', hint=hint) htiter = email.Iterators.typed_subpart_iterator(msg, subtype='html') try: html = htiter.next() except StopIteration: raise util.DeadMan('no html found') htmldir = tempfile.mkdtemp('', 'viewhtmlmsg.') try: htmlfile = os.path.join(htmldir, 'index.html') charset = html.get_param('charset') html = html.get_payload(decode=True) if charset: charsetmeta = '<meta charset="%s">' % charset if '<head>' in html: html = html.replace('<head>', '<head>%s' % charsetmeta) else: html = '<head>%s</head>%s' % (charsetmeta, html) fc = 0 for part in msg.walk(): fc += 1 fn = (part.get_filename() or part.get_param('filename') or part.get_param('name', 'prefix_%d' % fc)) if part['content-id']: # safe ascii filename: replace it with cid fn = email.Utils.unquote(part['content-id']) html = html.replace('"cid:%s"' % fn, "%s" % fn) fpay = part.get_payload(decode=True) if fpay: fp = open(os.path.join(htmldir, fn), 'wb') fp.write(fpay) fp.close() if self.safe: spat = r'(src|background)\s*=\s*["\']??https??://[^"\'>]*["\'>]' html = re.sub(spat, r'\1="#"', html) fp = open(htmlfile, 'wb') fp.write(html) fp.close() self.items = [htmlfile] if self.keep: try: self.ivisit() except NameError: self.urlvisit() time.sleep(self.keep) else: self.urlvisit() finally: self.cleanup(htmldir)
def maskompile(self): try: self.ui.mask = re.compile(r'%s' % self.ui.mask) except re.error, inst: raise util.DeadMan("%s in pattern `%s'" % (inst, self.ui.mask))
def _mrex(pat): '''Checks and returns MULTILINE regex of pat.''' try: return re.compile(r'%s' % pat, re.MULTILINE) except re.error, inst: raise util.DeadMan("error in pattern `%s': %s" % (pat, inst))