Esempio n. 1
0
File: thread.py Progetto: t-8ch/alot
    def apply(self, ui):
        # look if this makes sense: do we have any accounts set up?
        my_accounts = settings.get_accounts()
        if not my_accounts:
            ui.notify('no accounts set', priority='error')
            return

        # get message to forward if not given in constructor
        if not self.message:
            self.message = ui.current_buffer.get_selected_message()
        mail = self.message.get_email()

        envelope = Envelope()

        if self.inline:  # inline mode
            # set body text
            name, address = self.message.get_author()
            timestamp = self.message.get_date()
            qf = settings.get_hook('forward_prefix')
            if qf:
                quote = qf(name, address, timestamp, ui=ui, dbm=ui.dbman)
            else:
                quote = 'Forwarded message from %s (%s):\n' % (name or address,
                                                               timestamp)
            mailcontent = quote
            quotehook = settings.get_hook('text_quote')
            if quotehook:
                mailcontent += quotehook(self.message.accumulate_body())
            else:
                quote_prefix = settings.get('quote_prefix')
                for line in self.message.accumulate_body().splitlines():
                    mailcontent += quote_prefix + line + '\n'

            envelope.body = mailcontent

        else:  # attach original mode
            # attach original msg
            mail.set_type('message/rfc822')
            mail['Content-Disposition'] = 'attachment'
            envelope.attach(Attachment(mail))

        # copy subject
        subject = decode_header(mail.get('Subject', ''))
        subject = 'Fwd: ' + subject
        forward_subject_hook = settings.get_hook('forward_subject')
        if forward_subject_hook:
            subject = forward_subject_hook(subject)
        else:
            fsp = settings.get('forward_subject_prefix')
            if not subject.startswith(('Fwd:', fsp)):
                subject = fsp + subject
        envelope.add('Subject', subject)

        # set From
        realname, address = recipient_to_from(mail, my_accounts)
        envelope.add('From', '%s <%s>' % (realname, address))

        # continue to compose
        ui.apply_command(
            ComposeCommand(envelope=envelope, spawn=self.force_spawn))
Esempio n. 2
0
    def apply(self, ui):
        # look if this makes sense: do we have any accounts set up?
        my_accounts = settings.get_accounts()
        if not my_accounts:
            ui.notify('no accounts set', priority='error')
            return

        # get message to forward if not given in constructor
        if not self.message:
            self.message = ui.current_buffer.get_selected_message()
        mail = self.message.get_email()

        envelope = Envelope()

        if self.inline:  # inline mode
            # set body text
            name, address = self.message.get_author()
            timestamp = self.message.get_date()
            qf = settings.get_hook('forward_prefix')
            if qf:
                quote = qf(name, address, timestamp, ui=ui, dbm=ui.dbman)
            else:
                quote = 'Forwarded message from %s (%s):\n' % (
                    name or address, timestamp)
            mailcontent = quote
            quotehook = settings.get_hook('text_quote')
            if quotehook:
                mailcontent += quotehook(self.message.accumulate_body())
            else:
                quote_prefix = settings.get('quote_prefix')
                for line in self.message.accumulate_body().splitlines():
                    mailcontent += quote_prefix + line + '\n'

            envelope.body = mailcontent

        else:  # attach original mode
            # attach original msg
            mail.set_type('message/rfc822')
            mail['Content-Disposition'] = 'attachment'
            envelope.attach(Attachment(mail))

        # copy subject
        subject = decode_header(mail.get('Subject', ''))
        subject = 'Fwd: ' + subject
        forward_subject_hook = settings.get_hook('forward_subject')
        if forward_subject_hook:
            subject = forward_subject_hook(subject)
        else:
            fsp = settings.get('forward_subject_prefix')
            if not subject.startswith(('Fwd:', fsp)):
                subject = fsp + subject
        envelope.add('Subject', subject)

        # set From
        realname, address = recipient_to_from(mail, my_accounts)
        envelope.add('From', '%s <%s>' % (realname, address))

        # continue to compose
        ui.apply_command(ComposeCommand(envelope=envelope,
                                        spawn=self.force_spawn))
Esempio n. 3
0
def main():
    """The main entry point to alot.  It parses the command line and prepares
    for the user interface main loop to run."""
    options, command = parser()

    # logging
    root_logger = logging.getLogger()
    for log_handler in root_logger.handlers:
        root_logger.removeHandler(log_handler)
    root_logger = None
    numeric_loglevel = getattr(logging, options.debug_level.upper(), None)
    logformat = '%(levelname)s:%(module)s:%(message)s'
    logging.basicConfig(level=numeric_loglevel, filename=options.logfile,
                        filemode='w', format=logformat)

    # locate alot config files
    if options.config is None:
        alotconfig = os.path.join(
            os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')),
            'alot', 'config')
        if os.path.exists(alotconfig):
            settings.alot_rc_path = alotconfig
    else:
        settings.alot_rc_path = options.config

    settings.notmuch_rc_path = options.notmuch_config

    try:
        settings.read_config()
        settings.read_notmuch_config()
    except (ConfigError, OSError, IOError) as e:
        sys.exit(e)

    # store options given by config swiches to the settingsManager:
    if options.colour_mode:
        settings.set('colourmode', options.colour_mode)

    # get ourselves a database manager
    indexpath = settings.get_notmuch_setting('database', 'path')
    indexpath = options.mailindex_path or indexpath
    dbman = DBManager(path=indexpath, ro=options.read_only)

    # determine what to do
    if command is None:
        try:
            cmdstring = settings.get('initial_command')
        except CommandParseError as err:
            sys.exit(err)
    elif command.subcommand in _SUBCOMMANDS:
        cmdstring = ' '.join(options.command)

    # set up and start interface
    UI(dbman, cmdstring)

    # run the exit hook
    exit_hook = settings.get_hook('exit')
    if exit_hook is not None:
        exit_hook()
Esempio n. 4
0
def main():
    """The main entry point to alot.  It parses the command line and prepares
    for the user interface main loop to run."""
    options, command = parser()

    # logging
    root_logger = logging.getLogger()
    for log_handler in root_logger.handlers:
        root_logger.removeHandler(log_handler)
    root_logger = None
    numeric_loglevel = getattr(logging, options.debug_level.upper(), None)
    logformat = '%(levelname)s:%(module)s:%(message)s'
    logging.basicConfig(level=numeric_loglevel,
                        filename=options.logfile,
                        filemode='w',
                        format=logformat)

    # locate alot config files
    if options.config is None:
        alotconfig = os.path.join(
            os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')),
            'alot', 'config')
        if not os.path.exists(alotconfig):
            alotconfig = None
    else:
        alotconfig = options.config

    try:
        settings.read_config(alotconfig)
        settings.read_notmuch_config(options.notmuch_config)
    except (ConfigError, OSError, IOError) as e:
        sys.exit(e)

    # store options given by config swiches to the settingsManager:
    if options.colour_mode:
        settings.set('colourmode', options.colour_mode)

    # get ourselves a database manager
    indexpath = settings.get_notmuch_setting('database', 'path')
    indexpath = options.mailindex_path or indexpath
    dbman = DBManager(path=indexpath, ro=options.read_only)

    # determine what to do
    if command is None:
        try:
            cmdstring = settings.get('initial_command')
        except CommandParseError as err:
            sys.exit(err)
    elif command.subcommand in _SUBCOMMANDS:
        cmdstring = ' '.join(options.command)

    # set up and start interface
    UI(dbman, cmdstring)

    # run the exit hook
    exit_hook = settings.get_hook('exit')
    if exit_hook is not None:
        exit_hook()
Esempio n. 5
0
    def apply(self, ui):
        logging.info('open attachment')
        mimetype = self.attachment.get_content_type()

        # returns pair of preliminary command string and entry dict containing
        # more info. We only use the dict and construct the command ourselves
        _, entry = settings.mailcap_find_match(mimetype)
        if entry:
            afterwards = None  # callback, will rm tempfile if used
            handler_stdin = None
            tempfile_name = None
            handler_raw_commandstring = entry['view']
            # read parameter
            part = self.attachment.get_mime_representation()
            parms = tuple(map('='.join, part.get_params()))

            # in case the mailcap defined command contains no '%s',
            # we pipe the files content to the handling command via stdin
            if '%s' in handler_raw_commandstring:
                nametemplate = entry.get('nametemplate', '%s')
                prefix, suffix = parse_mailcap_nametemplate(nametemplate)

                fn_hook = settings.get_hook('sanitize_attachment_filename')
                if fn_hook:
                    # get filename
                    filename = self.attachment.get_filename()
                    prefix, suffix = fn_hook(filename, prefix, suffix)

                tmpfile = tempfile.NamedTemporaryFile(delete=False,
                                                      prefix=prefix,
                                                      suffix=suffix)

                tempfile_name = tmpfile.name
                self.attachment.write(tmpfile)
                tmpfile.close()

                def afterwards():
                    os.unlink(tempfile_name)
            else:
                handler_stdin = StringIO()
                self.attachment.write(handler_stdin)

            # create handler command list
            handler_cmd = mailcap.subst(handler_raw_commandstring, mimetype,
                                        filename=tempfile_name, plist=parms)

            handler_cmdlist = split_commandstring(handler_cmd)

            # 'needsterminal' makes handler overtake the terminal
            nt = entry.get('needsterminal', None)
            overtakes = (nt is None)

            ui.apply_command(ExternalCommand(handler_cmdlist,
                                             stdin=handler_stdin,
                                             on_success=afterwards,
                                             thread=overtakes))
        else:
            ui.notify('unknown mime type')
Esempio n. 6
0
    def __init__(self,
                 cmd,
                 stdin=None,
                 shell=False,
                 spawn=False,
                 refocus=True,
                 thread=False,
                 on_success=None,
                 **kwargs):
        """
        :param cmd: the command to call
        :type cmd: list or str
        :param stdin: input to pipe to the process
        :type stdin: file or str
        :param spawn: run command in a new terminal
        :type spawn: bool
        :param shell: let shell interpret command string
        :type shell: bool
        :param thread: run asynchronously, don't block alot
        :type thread: bool
        :param refocus: refocus calling buffer after cmd termination
        :type refocus: bool
        :param on_success: code to execute after command successfully exited
        :type on_success: callable
        """
        logging.debug({'spawn': spawn})
        # make sure cmd is a list of str
        if isinstance(cmd, unicode):
            # convert cmdstring to list: in case shell==True,
            # Popen passes only the first item in the list to $SHELL
            cmd = [cmd] if shell else split_commandstring(cmd)

        # determine complete command list to pass
        touchhook = settings.get_hook('touch_external_cmdlist')
        # filter cmd, shell and thread through hook if defined
        if touchhook is not None:
            logging.debug('calling hook: touch_external_cmdlist')
            res = touchhook(cmd, shell=shell, spawn=spawn, thread=thread)
            logging.debug('got: %s' % res)
            cmd, shell, self.in_thread = res
        # otherwise if spawn requested and X11 is running
        elif spawn:
            if 'DISPLAY' in os.environ:
                term_cmd = settings.get('terminal_cmd', '')
                logging.info('spawn in terminal: %s' % term_cmd)
                termcmdlist = split_commandstring(term_cmd)
                cmd = termcmdlist + cmd
            else:
                thread = False

        self.cmdlist = cmd
        self.stdin = stdin
        self.shell = shell
        self.refocus = refocus
        self.in_thread = thread
        self.on_success = on_success
        Command.__init__(self, **kwargs)
Esempio n. 7
0
    def __init__(
        self, cmd, stdin=None, shell=False, spawn=False, refocus=True, thread=False, on_success=None, **kwargs
    ):
        """
        :param cmd: the command to call
        :type cmd: list or str
        :param stdin: input to pipe to the process
        :type stdin: file or str
        :param spawn: run command in a new terminal
        :type spawn: bool
        :param shell: let shell interpret command string
        :type shell: bool
        :param thread: run asynchronously, don't block alot
        :type thread: bool
        :param refocus: refocus calling buffer after cmd termination
        :type refocus: bool
        :param on_success: code to execute after command successfully exited
        :type on_success: callable
        """
        logging.debug({"spawn": spawn})
        # make sure cmd is a list of str
        if isinstance(cmd, unicode):
            # convert cmdstring to list: in case shell==True,
            # Popen passes only the first item in the list to $SHELL
            cmd = [cmd] if shell else split_commandstring(cmd)

        # determine complete command list to pass
        touchhook = settings.get_hook("touch_external_cmdlist")
        # filter cmd, shell and thread through hook if defined
        if touchhook is not None:
            logging.debug("calling hook: touch_external_cmdlist")
            res = touchhook(cmd, shell=shell, spawn=spawn, thread=thread)
            logging.debug("got: %s" % res)
            cmd, shell, self.in_thread = res
        # otherwise if spawn requested and X11 is running
        elif spawn:
            if "DISPLAY" in os.environ:
                term_cmd = settings.get("terminal_cmd", "")
                logging.info("spawn in terminal: %s" % term_cmd)
                termcmdlist = split_commandstring(term_cmd)
                cmd = termcmdlist + cmd
            else:
                thread = False

        self.cmdlist = cmd
        self.stdin = stdin
        self.shell = shell
        self.refocus = refocus
        self.in_thread = thread
        self.on_success = on_success
        Command.__init__(self, **kwargs)
Esempio n. 8
0
        def openEnvelopeFromTmpfile():
            # This parses the input from the tempfile.
            # we do this ourselves here because we want to be able to
            # just type utf-8 encoded stuff into the tempfile and let alot
            # worry about encodings.

            # get input
            # tempfile will be removed on buffer cleanup
            f = open(self.envelope.tmpfile.name)
            enc = settings.get('editor_writes_encoding')
            template = string_decode(f.read(), enc)
            f.close()

            # call post-edit translate hook
            translate = settings.get_hook('post_edit_translate')
            if translate:
                template = translate(template, ui=ui, dbm=ui.dbman)
            self.envelope.parse_template(template,
                                         only_body=self.edit_only_body)
            if self.openNew:
                ui.buffer_open(buffers.EnvelopeBuffer(ui, self.envelope))
            else:
                ebuffer.envelope = self.envelope
                ebuffer.rebuild()
Esempio n. 9
0
        def openEnvelopeFromTmpfile():
            # This parses the input from the tempfile.
            # we do this ourselves here because we want to be able to
            # just type utf-8 encoded stuff into the tempfile and let alot
            # worry about encodings.

            # get input
            # tempfile will be removed on buffer cleanup
            f = open(self.envelope.tmpfile.name)
            enc = settings.get('editor_writes_encoding')
            template = string_decode(f.read(), enc)
            f.close()

            # call post-edit translate hook
            translate = settings.get_hook('post_edit_translate')
            if translate:
                template = translate(template, ui=ui, dbm=ui.dbman)
            self.envelope.parse_template(template,
                                         only_body=self.edit_only_body)
            if self.openNew:
                ui.buffer_open(buffers.EnvelopeBuffer(ui, self.envelope))
            else:
                ebuffer.envelope = self.envelope
                ebuffer.rebuild()
Esempio n. 10
0
File: thread.py Progetto: t-8ch/alot
    def apply(self, ui):
        # look if this makes sense: do we have any accounts set up?
        my_accounts = settings.get_accounts()
        if not my_accounts:
            ui.notify('no accounts set', priority='error')
            return

        # get message to forward if not given in constructor
        if not self.message:
            self.message = ui.current_buffer.get_selected_message()
        mail = self.message.get_email()

        # set body text
        name, address = self.message.get_author()
        timestamp = self.message.get_date()
        qf = settings.get_hook('reply_prefix')
        if qf:
            quotestring = qf(name, address, timestamp, ui=ui, dbm=ui.dbman)
        else:
            quotestring = 'Quoting %s (%s)\n' % (name or address, timestamp)
        mailcontent = quotestring
        quotehook = settings.get_hook('text_quote')
        if quotehook:
            mailcontent += quotehook(self.message.accumulate_body())
        else:
            quote_prefix = settings.get('quote_prefix')
            for line in self.message.accumulate_body().splitlines():
                mailcontent += quote_prefix + line + '\n'

        envelope = Envelope(bodytext=mailcontent)

        # copy subject
        subject = decode_header(mail.get('Subject', ''))
        reply_subject_hook = settings.get_hook('reply_subject')
        if reply_subject_hook:
            subject = reply_subject_hook(subject)
        else:
            rsp = settings.get('reply_subject_prefix')
            if not subject.startswith(('Re:', rsp)):
                subject = rsp + subject
        envelope.add('Subject', subject)

        # set From
        realname, address = recipient_to_from(mail, my_accounts)
        envelope.add('From', '%s <%s>' % (realname, address))

        # set To
        sender = mail['Reply-To'] or mail['From']
        recipients = [sender]
        my_addresses = settings.get_addresses()
        if self.groupreply:
            if sender != mail['From']:
                recipients.append(mail['From'])
            cleared = self.clear_my_address(my_addresses, mail.get('To', ''))
            recipients.append(cleared)

            # copy cc for group-replies
            if 'Cc' in mail:
                cc = self.clear_my_address(my_addresses, mail['Cc'])
                envelope.add('Cc', decode_header(cc))

        to = ', '.join(recipients)
        logging.debug('reply to: %s' % to)
        envelope.add('To', decode_header(to))

        # set In-Reply-To header
        envelope.add('In-Reply-To', '<%s>' % self.message.get_message_id())

        # set References header
        old_references = mail.get('References', '')
        if old_references:
            old_references = old_references.split()
            references = old_references[-8:]
            if len(old_references) > 8:
                references = old_references[:1] + references
            references.append('<%s>' % self.message.get_message_id())
            envelope.add('References', ' '.join(references))
        else:
            envelope.add('References', '<%s>' % self.message.get_message_id())

        # continue to compose
        ui.apply_command(
            ComposeCommand(envelope=envelope, spawn=self.force_spawn))
Esempio n. 11
0
    def apply(self, ui):
        ebuffer = ui.current_buffer
        if not self.envelope:
            self.envelope = ui.current_buffer.envelope

        #determine editable headers
        edit_headers = set(settings.get('edit_headers_whitelist'))
        if '*' in edit_headers:
            edit_headers = set(self.envelope.headers.keys())
        blacklist = set(settings.get('edit_headers_blacklist'))
        if '*' in blacklist:
            blacklist = set(self.envelope.headers.keys())
        edit_headers = edit_headers - blacklist
        logging.info('editable headers: %s' % edit_headers)

        def openEnvelopeFromTmpfile():
            # This parses the input from the tempfile.
            # we do this ourselves here because we want to be able to
            # just type utf-8 encoded stuff into the tempfile and let alot
            # worry about encodings.

            # get input
            # tempfile will be removed on buffer cleanup
            f = open(self.envelope.tmpfile.name)
            enc = settings.get('editor_writes_encoding')
            template = string_decode(f.read(), enc)
            f.close()

            # call post-edit translate hook
            translate = settings.get_hook('post_edit_translate')
            if translate:
                template = translate(template, ui=ui, dbm=ui.dbman)
            self.envelope.parse_template(template,
                                         only_body=self.edit_only_body)
            if self.openNew:
                ui.buffer_open(buffers.EnvelopeBuffer(ui, self.envelope))
            else:
                ebuffer.envelope = self.envelope
                ebuffer.rebuild()

        # decode header
        headertext = u''
        for key in edit_headers:
            vlist = self.envelope.get_all(key)
            if not vlist:
                # ensure editable headers are present in template
                vlist = ['']
            else:
                # remove to be edited lines from envelope
                del self.envelope[key]

            for value in vlist:
                # newlines (with surrounding spaces) by spaces in values
                value = value.strip()
                value = re.sub('[ \t\r\f\v]*\n[ \t\r\f\v]*', ' ', value)
                headertext += '%s: %s\n' % (key, value)

        # determine editable content
        bodytext = self.envelope.body
        if headertext:
            content = '%s\n%s' % (headertext, bodytext)
            self.edit_only_body = False
        else:
            content = bodytext
            self.edit_only_body = True

        # call pre-edit translate hook
        translate = settings.get_hook('pre_edit_translate')
        if translate:
            content = translate(content, ui=ui, dbm=ui.dbman)

        #write stuff to tempfile
        old_tmpfile = None
        if self.envelope.tmpfile:
            old_tmpfile = self.envelope.tmpfile
        self.envelope.tmpfile = tempfile.NamedTemporaryFile(delete=False,
                                                            prefix='alot.')
        self.envelope.tmpfile.write(content.encode('utf-8'))
        self.envelope.tmpfile.flush()
        self.envelope.tmpfile.close()
        if old_tmpfile:
            os.unlink(old_tmpfile.name)
        cmd = globals.EditCommand(self.envelope.tmpfile.name,
                                  on_success=openEnvelopeFromTmpfile, spawn=self.force_spawn,
                                  thread=self.force_spawn, refocus=self.refocus)
        ui.apply_command(cmd)
Esempio n. 12
0
    indexpath = settings.get_notmuch_setting('database', 'path')
    indexpath = args['mailindex-path'] or indexpath
    dbman = DBManager(path=indexpath, ro=args['read-only'])

    # determine what to do
    try:
        if args.subCommand == 'search':
            query = ' '.join(args.subOptions.args)
            cmdstring = 'search %s %s' % (args.subOptions.as_argparse_opts(),
                                          query)
        elif args.subCommand == 'compose':
            cmdstring = 'compose %s' % args.subOptions.as_argparse_opts()
            if args.subOptions.rest is not None:
                cmdstring += ' ' + args.subOptions.rest
        else:
            cmdstring = settings.get('initial_command')
    except CommandParseError, e:
        sys.exit(e)

    # set up and start interface
    UI(dbman, cmdstring)

    # run the exit hook
    exit_hook = settings.get_hook('exit')
    if exit_hook is not None:
        exit_hook()


if __name__ == "__main__":
    main()
Esempio n. 13
0
    def apply(self, ui):
        # get message to forward if not given in constructor
        if not self.message:
            self.message = ui.current_buffer.get_selected_message()
        mail = self.message.get_email()

        # set body text
        name, address = self.message.get_author()
        timestamp = self.message.get_date()
        qf = settings.get_hook('reply_prefix')
        if qf:
            quotestring = qf(name, address, timestamp, ui=ui, dbm=ui.dbman)
        else:
            quotestring = 'Quoting %s (%s)\n' % (name or address, timestamp)
        mailcontent = quotestring
        quotehook = settings.get_hook('text_quote')
        if quotehook:
            mailcontent += quotehook(self.message.accumulate_body())
        else:
            quote_prefix = settings.get('quote_prefix')
            for line in self.message.accumulate_body().splitlines():
                mailcontent += quote_prefix + line + '\n'

        envelope = Envelope(bodytext=mailcontent)

        # copy subject
        subject = decode_header(mail.get('Subject', ''))
        reply_subject_hook = settings.get_hook('reply_subject')
        if reply_subject_hook:
            subject = reply_subject_hook(subject)
        else:
            rsp = settings.get('reply_subject_prefix')
            if not subject.lower().startswith(('re:', rsp.lower())):
                subject = rsp + subject
        envelope.add('Subject', subject)

        # Auto-detect ML
        auto_replyto_mailinglist = settings.get('auto_replyto_mailinglist')
        if mail['List-Id'] and self.listreply is None:
            # mail['List-Id'] is need to enable reply-to-list
            self.listreply = auto_replyto_mailinglist
        elif mail['List-Id'] and self.listreply is True:
            self.listreply = True
        elif self.listreply is False:
            # In this case we only need the sender
            self.listreply = False

        # set From-header and sending account
        try:
            from_header, account = determine_sender(mail, 'reply')
        except AssertionError as e:
            ui.notify(e.message, priority='error')
            return
        envelope.add('From', from_header)

        # set To
        sender = mail['Reply-To'] or mail['From']
        my_addresses = settings.get_addresses()
        sender_address = parseaddr(sender)[1]
        cc = ''

        # check if reply is to self sent message
        if sender_address in my_addresses:
            recipients = [mail['To']]
            emsg = 'Replying to own message, set recipients to: %s' \
                % recipients
            logging.debug(emsg)
        else:
            recipients = [sender]

        if self.groupreply:
            # make sure that our own address is not included
            # if the message was self-sent, then our address is not included
            MFT = mail.get_all('Mail-Followup-To', [])
            followupto = self.clear_my_address(my_addresses, MFT)
            if followupto and settings.get('honor_followup_to'):
                logging.debug('honor followup to: %s', followupto)
                recipients = [followupto]
                # since Mail-Followup-To was set, ignore the Cc header
            else:
                if sender != mail['From']:
                    recipients.append(mail['From'])

                # append To addresses if not replying to self sent message
                if sender_address not in my_addresses:
                    cleared = self.clear_my_address(
                        my_addresses, mail.get_all('To', []))
                    recipients.append(cleared)

                # copy cc for group-replies
                if 'Cc' in mail:
                    cc = self.clear_my_address(
                        my_addresses, mail.get_all('Cc', []))
                    envelope.add('Cc', decode_header(cc))

        to = ', '.join(recipients)
        logging.debug('reply to: %s' % to)

        if self.listreply:
            # To choose the target of the reply --list
            # Reply-To is standart reply target RFC 2822:, RFC 1036: 2.2.1
            # X-BeenThere is needed by sourceforge ML also winehq
            # X-Mailing-List is also standart and is used by git-send-mail
            to = mail['Reply-To'] or mail['X-BeenThere'] or mail['X-Mailing-List']
            # Some mail server (gmail) will not resend you own mail, so you have
            # to deal with the one in sent
            if to is None:
                to = mail['To']
            logging.debug('mail list reply to: %s' % to)
            # Cleaning the 'To' in this case
            if envelope.get('To') is not None:
                envelope.__delitem__('To')

        # Finally setup the 'To' header
        envelope.add('To', decode_header(to))

        # if any of the recipients is a mailinglist that we are subscribed to,
        # set Mail-Followup-To header so that duplicates are avoided
        if settings.get('followup_to'):
            # to and cc are already cleared of our own address
            allrecipients = [to] + [cc]
            lists = settings.get('mailinglists')
            # check if any recipient address matches a known mailing list
            if any([addr in lists for n, addr in getaddresses(allrecipients)]):
                followupto = ', '.join(allrecipients)
                logging.debug('mail followup to: %s' % followupto)
                envelope.add('Mail-Followup-To', decode_header(followupto))

        # set In-Reply-To header
        envelope.add('In-Reply-To', '<%s>' % self.message.get_message_id())

        # set References header
        old_references = mail.get('References', '')
        if old_references:
            old_references = old_references.split()
            references = old_references[-8:]
            if len(old_references) > 8:
                references = old_references[:1] + references
            references.append('<%s>' % self.message.get_message_id())
            envelope.add('References', ' '.join(references))
        else:
            envelope.add('References', '<%s>' % self.message.get_message_id())

        # continue to compose
        encrypt = mail.get_content_subtype() == 'encrypted'
        ui.apply_command(ComposeCommand(envelope=envelope,
                                        spawn=self.force_spawn,
                                        encrypt=encrypt))
Esempio n. 14
0
    def apply(self, ui):
        # look if this makes sense: do we have any accounts set up?
        my_accounts = settings.get_accounts()
        if not my_accounts:
            ui.notify('no accounts set', priority='error')
            return

        # get message to forward if not given in constructor
        if not self.message:
            self.message = ui.current_buffer.get_selected_message()
        mail = self.message.get_email()

        # set body text
        name, address = self.message.get_author()
        timestamp = self.message.get_date()
        qf = settings.get_hook('reply_prefix')
        if qf:
            quotestring = qf(name, address, timestamp, ui=ui, dbm=ui.dbman)
        else:
            quotestring = 'Quoting %s (%s)\n' % (name, timestamp)
        mailcontent = quotestring
        for line in self.message.accumulate_body().splitlines():
            mailcontent += '>' + line + '\n'

        envelope = Envelope(bodytext=mailcontent)

        # copy subject
        subject = decode_header(mail.get('Subject', ''))
        if not subject.startswith('Re:'):
            subject = 'Re: ' + subject
        envelope.add('Subject', subject)

        # set From
        realname, address = recipient_to_from(mail, my_accounts)
        envelope.add('From', '%s <%s>' % (realname, address))

        # set To
        sender = mail['Reply-To'] or mail['From']
        recipients = [sender]
        my_addresses = settings.get_addresses()
        if self.groupreply:
            if sender != mail['From']:
                recipients.append(mail['From'])
            cleared = self.clear_my_address(my_addresses, mail.get('To', ''))
            recipients.append(cleared)

            # copy cc for group-replies
            if 'Cc' in mail:
                cc = self.clear_my_address(my_addresses, mail['Cc'])
                envelope.add('Cc', decode_header(cc))

        to = ', '.join(recipients)
        logging.debug('reply to: %s' % to)
        envelope.add('To', decode_header(to))

        # set In-Reply-To header
        envelope.add('In-Reply-To', '<%s>' % self.message.get_message_id())

        # set References header
        old_references = mail.get('References', '')
        if old_references:
            old_references = old_references.split()
            references = old_references[-8:]
            if len(old_references) > 8:
                references = old_references[:1] + references
            references.append('<%s>' % self.message.get_message_id())
            envelope.add('References', ' '.join(references))
        else:
            envelope.add('References', '<%s>' % self.message.get_message_id())

        # continue to compose
        ui.apply_command(ComposeCommand(envelope=envelope,
                                        spawn=self.force_spawn))
Esempio n. 15
0
    def apply(self, ui):
        # get message to forward if not given in constructor
        if not self.message:
            self.message = ui.current_buffer.get_selected_message()
        mail = self.message.get_email()

        # set body text
        name, address = self.message.get_author()
        timestamp = self.message.get_date()
        qf = settings.get_hook('reply_prefix')
        if qf:
            quotestring = qf(name, address, timestamp, ui=ui, dbm=ui.dbman)
        else:
            quotestring = 'Quoting %s (%s)\n' % (name or address, timestamp)
        mailcontent = quotestring
        quotehook = settings.get_hook('text_quote')
        if quotehook:
            mailcontent += quotehook(self.message.accumulate_body())
        else:
            quote_prefix = settings.get('quote_prefix')
            for line in self.message.accumulate_body().splitlines():
                mailcontent += quote_prefix + line + '\n'

        envelope = Envelope(bodytext=mailcontent)

        # copy subject
        subject = decode_header(mail.get('Subject', ''))
        reply_subject_hook = settings.get_hook('reply_subject')
        if reply_subject_hook:
            subject = reply_subject_hook(subject)
        else:
            rsp = settings.get('reply_subject_prefix')
            if not subject.startswith(('Re:', rsp)):
                subject = rsp + subject
        envelope.add('Subject', subject)

        # set From-header and sending account
        try:
            from_header, account = determine_sender(mail, 'reply')
        except AssertionError as e:
            ui.notify(e.message, priority='error')
            return
        envelope.add('From', from_header)

        # set To
        sender = mail['Reply-To'] or mail['From']
        recipients = [sender]
        my_addresses = settings.get_addresses()
        if self.groupreply:
            if sender != mail['From']:
                recipients.append(mail['From'])
            cleared = self.clear_my_address(my_addresses, mail.get('To', ''))
            recipients.append(cleared)

            # copy cc for group-replies
            if 'Cc' in mail:
                cc = self.clear_my_address(my_addresses, mail['Cc'])
                envelope.add('Cc', decode_header(cc))

        to = ', '.join(recipients)
        logging.debug('reply to: %s' % to)
        envelope.add('To', decode_header(to))

        # set In-Reply-To header
        envelope.add('In-Reply-To', '<%s>' % self.message.get_message_id())

        # set References header
        old_references = mail.get('References', '')
        if old_references:
            old_references = old_references.split()
            references = old_references[-8:]
            if len(old_references) > 8:
                references = old_references[:1] + references
            references.append('<%s>' % self.message.get_message_id())
            envelope.add('References', ' '.join(references))
        else:
            envelope.add('References', '<%s>' % self.message.get_message_id())

        # continue to compose
        ui.apply_command(ComposeCommand(envelope=envelope,
                                        spawn=self.force_spawn))
Esempio n. 16
0
def main():
    # interpret cml arguments
    args = Options()
    try:
        args.parseOptions()  # When given no argument, parses sys.argv[1:]
    except usage.UsageError as errortext:
        print('%s' % errortext)
        print('Try --help for usage details.')
        sys.exit(1)

    # logging
    root_logger = logging.getLogger()
    for log_handler in root_logger.handlers:
        root_logger.removeHandler(log_handler)
    root_logger = None
    numeric_loglevel = getattr(logging, args['debug-level'].upper(), None)
    logfilename = os.path.expanduser(args['logfile'])
    logformat = '%(levelname)s:%(module)s:%(message)s'
    logging.basicConfig(level=numeric_loglevel,
                        filename=logfilename,
                        filemode='w',
                        format=logformat)

    # locate alot config files
    configfiles = [
        os.path.join(
            os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')),
            'alot', 'config'),
    ]
    if args['config']:
        expanded_path = os.path.expanduser(args['config'])
        if not os.path.exists(expanded_path):
            msg = 'Config file "%s" does not exist. Goodbye for now.'
            sys.exit(msg % expanded_path)
        configfiles.insert(0, expanded_path)

    # locate notmuch config
    notmuchpath = os.environ.get('NOTMUCH_CONFIG', '~/.notmuch-config')
    if args['notmuch-config']:
        notmuchpath = args['notmuch-config']
    notmuchconfig = os.path.expanduser(notmuchpath)

    alotconfig = None
    # read the first alot config file we find
    for configfilename in configfiles:
        if os.path.exists(configfilename):
            alotconfig = configfilename
            break  # use only the first

    try:
        settings.read_config(alotconfig)
        settings.read_notmuch_config(notmuchconfig)
    except (ConfigError, OSError, IOError) as e:
        sys.exit(e)

    # store options given by config swiches to the settingsManager:
    if args['colour-mode']:
        settings.set('colourmode', args['colour-mode'])

    # get ourselves a database manager
    indexpath = settings.get_notmuch_setting('database', 'path')
    indexpath = args['mailindex-path'] or indexpath
    dbman = DBManager(path=indexpath, ro=args['read-only'])

    # determine what to do
    try:
        if args.subCommand == 'search':
            query = ' '.join(args.subOptions.args)
            cmdstring = 'search %s %s' % (args.subOptions.as_argparse_opts(),
                                          query)
        elif args.subCommand == 'compose':
            cmdstring = 'compose %s' % args.subOptions.as_argparse_opts()
            if args.subOptions.rest is not None:
                cmdstring += ' ' + args.subOptions.rest
        else:
            cmdstring = settings.get('initial_command')
    except CommandParseError as e:
        sys.exit(e)

    # set up and start interface
    UI(dbman, cmdstring)

    # run the exit hook
    exit_hook = settings.get_hook('exit')
    if exit_hook is not None:
        exit_hook()
Esempio n. 17
0
File: thread.py Progetto: vrs/alot
    def apply(self, ui):
        # get message to forward if not given in constructor
        if not self.message:
            self.message = ui.current_buffer.get_selected_message()
        mail = self.message.get_email()

        envelope = Envelope()

        if self.inline:  # inline mode
            # set body text
            name, address = self.message.get_author()
            timestamp = self.message.get_date()
            qf = settings.get_hook('forward_prefix')
            if qf:
                quote = qf(name, address, timestamp, ui=ui, dbm=ui.dbman)
            else:
                quote = 'Forwarded message from %s (%s):\n' % (
                    name or address, timestamp)
            mailcontent = quote
            quotehook = settings.get_hook('text_quote')
            if quotehook:
                mailcontent += quotehook(self.message.accumulate_body())
            else:
                quote_prefix = settings.get('quote_prefix')
                for line in self.message.accumulate_body().splitlines():
                    mailcontent += quote_prefix + line + '\n'

            envelope.body = mailcontent

            for a in self.message.get_attachments():
                envelope.attach(a)

        else:  # attach original mode
            # attach original msg
            original_mail = Message()
            original_mail.set_type('message/rfc822')
            original_mail['Content-Disposition'] = 'attachment'
            original_mail.set_payload(email_as_string(mail))
            envelope.attach(Attachment(original_mail))

        # copy subject
        subject = decode_header(mail.get('Subject', ''))
        subject = 'Fwd: ' + subject
        forward_subject_hook = settings.get_hook('forward_subject')
        if forward_subject_hook:
            subject = forward_subject_hook(subject)
        else:
            fsp = settings.get('forward_subject_prefix')
            if not subject.startswith(('Fwd:', fsp)):
                subject = fsp + subject
        envelope.add('Subject', subject)

        # set From-header and sending account
        try:
            from_header, account = determine_sender(mail, 'reply')
        except AssertionError as e:
            ui.notify(e.message, priority='error')
            return
        envelope.add('From', from_header)

        # continue to compose
        ui.apply_command(ComposeCommand(envelope=envelope,
                                        spawn=self.force_spawn))
Esempio n. 18
0
    def apply(self, ui):
        # get message to forward if not given in constructor
        if not self.message:
            self.message = ui.current_buffer.get_selected_message()
        mail = self.message.get_email()

        # set body text
        name, address = self.message.get_author()
        timestamp = self.message.get_date()
        qf = settings.get_hook('reply_prefix')
        if qf:
            quotestring = qf(name, address, timestamp, ui=ui, dbm=ui.dbman)
        else:
            quotestring = 'Quoting %s (%s)\n' % (name or address, timestamp)
        mailcontent = quotestring
        quotehook = settings.get_hook('text_quote')
        if quotehook:
            mailcontent += quotehook(self.message.accumulate_body())
        else:
            quote_prefix = settings.get('quote_prefix')
            for line in self.message.accumulate_body().splitlines():
                mailcontent += quote_prefix + line + '\n'

        envelope = Envelope(bodytext=mailcontent)

        # copy subject
        subject = decode_header(mail.get('Subject', ''))
        reply_subject_hook = settings.get_hook('reply_subject')
        if reply_subject_hook:
            subject = reply_subject_hook(subject)
        else:
            rsp = settings.get('reply_subject_prefix')
            if not subject.lower().startswith(('re:', rsp.lower())):
                subject = rsp + subject
        envelope.add('Subject', subject)

        # set From-header and sending account
        try:
            from_header, account = determine_sender(mail, 'reply')
        except AssertionError as e:
            ui.notify(e.message, priority='error')
            return
        envelope.add('From', from_header)

        # set To
        sender = mail['Reply-To'] or mail['From']
        my_addresses = settings.get_addresses()
        sender_address = parseaddr(sender)[1]
        cc = ''

        # check if reply is to self sent message
        if sender_address in my_addresses:
            recipients = [mail['To']]
            emsg = 'Replying to own message, set recipients to: %s' \
                % recipients
            logging.debug(emsg)
        else:
            recipients = [sender]

        if self.groupreply:
            # make sure that our own address is not included
            # if the message was self-sent, then our address is not included
            MFT = mail.get_all('Mail-Followup-To', [])
            followupto = self.clear_my_address(my_addresses, MFT)
            if followupto and settings.get('honor_followup_to'):
                logging.debug('honor followup to: %s', followupto)
                recipients = [followupto]
                # since Mail-Followup-To was set, ignore the Cc header
            else:
                if sender != mail['From']:
                    recipients.append(mail['From'])

                # append To addresses if not replying to self sent message
                if sender_address not in my_addresses:
                    cleared = self.clear_my_address(my_addresses,
                                                    mail.get_all('To', []))
                    recipients.append(cleared)

                # copy cc for group-replies
                if 'Cc' in mail:
                    cc = self.clear_my_address(my_addresses,
                                               mail.get_all('Cc', []))
                    envelope.add('Cc', decode_header(cc))

        to = ', '.join(recipients)
        logging.debug('reply to: %s' % to)
        envelope.add('To', decode_header(to))

        # if any of the recipients is a mailinglist that we are subscribed to,
        # set Mail-Followup-To header so that duplicates are avoided
        if settings.get('followup_to'):
            # to and cc are already cleared of our own address
            allrecipients = [to] + [cc]
            lists = settings.get('mailinglists')
            # check if any recipient address matches a known mailing list
            if any([addr in lists for n, addr in getaddresses(allrecipients)]):
                followupto = ', '.join(allrecipients)
                logging.debug('mail followup to: %s' % followupto)
                envelope.add('Mail-Followup-To', decode_header(followupto))

        # set In-Reply-To header
        envelope.add('In-Reply-To', '<%s>' % self.message.get_message_id())

        # set References header
        old_references = mail.get('References', '')
        if old_references:
            old_references = old_references.split()
            references = old_references[-8:]
            if len(old_references) > 8:
                references = old_references[:1] + references
            references.append('<%s>' % self.message.get_message_id())
            envelope.add('References', ' '.join(references))
        else:
            envelope.add('References', '<%s>' % self.message.get_message_id())

        # continue to compose
        ui.apply_command(
            ComposeCommand(envelope=envelope, spawn=self.force_spawn))
Esempio n. 19
0
def main():
    # interpret cml arguments
    args = Options()
    try:
        args.parseOptions()  # When given no argument, parses sys.argv[1:]
    except usage.UsageError as errortext:
        print('%s' % errortext)
        print('Try --help for usage details.')
        sys.exit(1)

    # logging
    root_logger = logging.getLogger()
    for log_handler in root_logger.handlers:
        root_logger.removeHandler(log_handler)
    root_logger = None
    numeric_loglevel = getattr(logging, args['debug-level'].upper(), None)
    logfilename = os.path.expanduser(args['logfile'])
    logformat = '%(levelname)s:%(module)s:%(message)s'
    logging.basicConfig(level=numeric_loglevel, filename=logfilename,
                        filemode='w', format=logformat)

    # locate alot config files
    configfiles = [
        os.path.join(os.environ.get('XDG_CONFIG_HOME',
                                    os.path.expanduser('~/.config')),
                     'alot', 'config'),
    ]
    if args['config']:
        expanded_path = os.path.expanduser(args['config'])
        if not os.path.exists(expanded_path):
            msg = 'Config file "%s" does not exist. Goodbye for now.'
            sys.exit(msg % expanded_path)
        configfiles.insert(0, expanded_path)

    # locate notmuch config
    notmuchpath = os.environ.get('NOTMUCH_CONFIG', '~/.notmuch-config')
    if args['notmuch-config']:
        notmuchpath = args['notmuch-config']
    notmuchconfig = os.path.expanduser(notmuchpath)

    alotconfig = None
    # read the first alot config file we find
    for configfilename in configfiles:
        if os.path.exists(configfilename):
            alotconfig = configfilename
            break  # use only the first

    try:
        settings.read_config(alotconfig)
        settings.read_notmuch_config(notmuchconfig)
    except (ConfigError, OSError, IOError) as e:
        sys.exit(e)

    # store options given by config swiches to the settingsManager:
    if args['colour-mode']:
        settings.set('colourmode', args['colour-mode'])

    # get ourselves a database manager
    indexpath = settings.get_notmuch_setting('database', 'path')
    indexpath = args['mailindex-path'] or indexpath
    dbman = DBManager(path=indexpath, ro=args['read-only'])

    # determine what to do
    try:
        if args.subCommand == 'search':
            query = ' '.join(args.subOptions.args)
            cmdstring = 'search %s %s' % (args.subOptions.as_argparse_opts(),
                                          query)
        elif args.subCommand == 'compose':
            cmdstring = 'compose %s' % args.subOptions.as_argparse_opts()
            if args.subOptions.rest is not None:
                cmdstring += ' ' + args.subOptions.rest
        else:
            cmdstring = settings.get('initial_command')
    except CommandParseError as e:
        sys.exit(e)

    # set up and start interface
    UI(dbman, cmdstring)

    # run the exit hook
    exit_hook = settings.get_hook('exit')
    if exit_hook is not None:
        exit_hook()
Esempio n. 20
0
    def apply(self, ui):
        # get message to forward if not given in constructor
        if not self.message:
            self.message = ui.current_buffer.get_selected_message()
        mail = self.message.get_email()

        # set body text
        name, address = self.message.get_author()
        timestamp = self.message.get_date()
        qf = settings.get_hook('reply_prefix')
        if qf:
            quotestring = qf(name, address, timestamp, ui=ui, dbm=ui.dbman)
        else:
            quotestring = 'Quoting %s (%s)\n' % (name or address, timestamp)
        mailcontent = quotestring
        quotehook = settings.get_hook('text_quote')
        if quotehook:
            mailcontent += quotehook(self.message.accumulate_body())
        else:
            quote_prefix = settings.get('quote_prefix')
            for line in self.message.accumulate_body().splitlines():
                mailcontent += quote_prefix + line + '\n'

        envelope = Envelope(bodytext=mailcontent)

        # copy subject
        subject = decode_header(mail.get('Subject', ''))
        reply_subject_hook = settings.get_hook('reply_subject')
        if reply_subject_hook:
            subject = reply_subject_hook(subject)
        else:
            rsp = settings.get('reply_subject_prefix')
            if not subject.lower().startswith(('re:', rsp.lower())):
                subject = rsp + subject
        envelope.add('Subject', subject)

        # set From-header and sending account
        try:
            from_header, account = determine_sender(mail, 'reply')
        except AssertionError as e:
            ui.notify(e.message, priority='error')
            return
        envelope.add('From', from_header)

        # set To
        sender = mail['Reply-To'] or mail['From']
        my_addresses = settings.get_addresses()
        sender_address = parseaddr(sender)[1]
        cc = ''

        # check if reply is to self sent message
        if sender_address in my_addresses:
            recipients = [mail['To']]
            emsg = 'Replying to own message, set recipients to: %s' \
                % recipients
            logging.debug(emsg)
        else:
            recipients = [sender]

        if self.groupreply:
            # make sure that our own address is not included
            # if the message was self-sent, then our address is not included
            MFT = mail.get_all('Mail-Followup-To', [])
            followupto = self.clear_my_address(my_addresses, MFT)
            if followupto and settings.get('honor_followup_to'):
                logging.debug('honor followup to: %s', followupto)
                recipients = [followupto]
                # since Mail-Followup-To was set, ignore the Cc header
            else:
                if sender != mail['From']:
                    recipients.append(mail['From'])

                # append To addresses if not replying to self sent message
                if sender_address not in my_addresses:
                    cleared = self.clear_my_address(
                        my_addresses, mail.get_all('To', []))
                    recipients.append(cleared)

                # copy cc for group-replies
                if 'Cc' in mail:
                    cc = self.clear_my_address(
                        my_addresses, mail.get_all('Cc', []))
                    envelope.add('Cc', decode_header(cc))

        to = ', '.join(recipients)
        logging.debug('reply to: %s' % to)
        envelope.add('To', decode_header(to))

        # if any of the recipients is a mailinglist that we are subscribed to,
        # set Mail-Followup-To header so that duplicates are avoided
        if settings.get('followup_to'):
            # to and cc are already cleared of our own address
            allrecipients = [to] + [cc]
            lists = settings.get('mailinglists')
            # check if any recipient address matches a known mailing list
            if any([addr in lists for n, addr in getaddresses(allrecipients)]):
                followupto = ', '.join(allrecipients)
                logging.debug('mail followup to: %s' % followupto)
                envelope.add('Mail-Followup-To', decode_header(followupto))

        # set In-Reply-To header
        envelope.add('In-Reply-To', '<%s>' % self.message.get_message_id())

        # set References header
        old_references = mail.get('References', '')
        if old_references:
            old_references = old_references.split()
            references = old_references[-8:]
            if len(old_references) > 8:
                references = old_references[:1] + references
            references.append('<%s>' % self.message.get_message_id())
            envelope.add('References', ' '.join(references))
        else:
            envelope.add('References', '<%s>' % self.message.get_message_id())

        # continue to compose
        ui.apply_command(ComposeCommand(envelope=envelope,
                                        spawn=self.force_spawn))
Esempio n. 21
0
def main():
    # set up the parser to parse the command line options.
    parser = argparse.ArgumentParser()
    parser.add_argument('-v', '--version', action='version',
                        version=alot.__version__)
    parser.add_argument('-r', '--read-only', action='store_true',
                        help='open db in read only mode')
    parser.add_argument('-c', '--config', help='config file',
                        type=lambda x: argparse.FileType('r')(x).name)
    parser.add_argument('-n', '--notmuch-config', default=os.environ.get(
                            'NOTMUCH_CONFIG',
                            os.path.expanduser('~/.notmuch-config')),
                        type=lambda x: argparse.FileType('r')(x).name,
                        help='notmuch config')
    parser.add_argument('-C', '--colour-mode',
                        choices=(1, 16, 256), type=int, default=256,
                        help='terminal colour mode [default: %(default)s].')
    parser.add_argument('-p', '--mailindex-path', #type=directory,
                        help='path to notmuch index')
    parser.add_argument('-d', '--debug-level', default='info',
                        choices=('debug', 'info', 'warning', 'error'),
                        help='debug log [default: %(default)s]')
    parser.add_argument('-l', '--logfile', default='/dev/null',
                        type=lambda x: argparse.FileType('w')(x).name,
                        help='logfile [default: %(default)s]')
    # We will handle the subcommands in a seperate run of argparse as argparse
    # does not support optional subcommands until now.
    subcommands = ('search', 'compose', 'bufferlist', 'taglist', 'pyshell')
    parser.add_argument('command', nargs=argparse.REMAINDER,
                        help='possible subcommands are {}'.format(
                            ', '.join(subcommands)))
    options = parser.parse_args()
    if options.command:
        # We have a command after the initial options so we also parse that.
        # But we just use the parser that is already defined for the internal
        # command that will back this subcommand.
        parser = argparse.ArgumentParser()
        subparsers = parser.add_subparsers(dest='subcommand')
        for subcommand in subcommands:
            subparsers.add_parser(subcommand,
                                  parents=[COMMANDS['global'][subcommand][1]])
        command = parser.parse_args(options.command)
    else:
        command = None

    # logging
    root_logger = logging.getLogger()
    for log_handler in root_logger.handlers:
        root_logger.removeHandler(log_handler)
    root_logger = None
    numeric_loglevel = getattr(logging, options.debug_level.upper(), None)
    logformat = '%(levelname)s:%(module)s:%(message)s'
    logging.basicConfig(level=numeric_loglevel, filename=options.logfile,
                        filemode='w', format=logformat)

    # locate alot config files
    if options.config is None:
        alotconfig = os.path.join(
            os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')),
            'alot', 'config')
        if not os.path.exists(alotconfig):
            alotconfig = None
    else:
        alotconfig = options.config

    try:
        settings.read_config(alotconfig)
        settings.read_notmuch_config(options.notmuch_config)
    except (ConfigError, OSError, IOError) as e:
        sys.exit(e)

    # store options given by config swiches to the settingsManager:
    if options.colour_mode:
        settings.set('colourmode', options.colour_mode)

    # get ourselves a database manager
    indexpath = settings.get_notmuch_setting('database', 'path')
    indexpath = options.mailindex_path or indexpath
    dbman = DBManager(path=indexpath, ro=options.read_only)

    # determine what to do
    if command is None:
        try:
            cmdstring = settings.get('initial_command')
        except CommandParseError as err:
            sys.exit(err)
    elif command.subcommand in subcommands:
        cmdstring = ' '.join(options.command)

    # set up and start interface
    UI(dbman, cmdstring)

    # run the exit hook
    exit_hook = settings.get_hook('exit')
    if exit_hook is not None:
        exit_hook()
Esempio n. 22
0
def main():
    # interpret cml arguments
    args = Options()
    try:
        args.parseOptions()  # When given no argument, parses sys.argv[1:]
    except usage.UsageError as errortext:
        print "%s" % errortext
        print "Try --help for usage details."
        sys.exit(1)

    # logging
    root_logger = logging.getLogger()
    for log_handler in root_logger.handlers:
        root_logger.removeHandler(log_handler)
    root_logger = None
    numeric_loglevel = getattr(logging, args["debug-level"].upper(), None)
    logfilename = os.path.expanduser(args["logfile"])
    logformat = "%(levelname)s:%(module)s:%(message)s"
    logging.basicConfig(level=numeric_loglevel, filename=logfilename, filemode="w", format=logformat)

    # locate alot config files
    configfiles = [os.path.join(os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), "alot", "config")]
    if args["config"]:
        expanded_path = os.path.expanduser(args["config"])
        if not os.path.exists(expanded_path):
            msg = 'Config file "%s" does not exist. Goodbye for now.'
            sys.exit(msg % expanded_path)
        configfiles.insert(0, expanded_path)

    # locate notmuch config
    notmuchpath = os.environ.get("NOTMUCH_CONFIG", "~/.notmuch-config")
    if args["notmuch-config"]:
        notmuchpath = args["notmuch-config"]
    notmuchconfig = os.path.expanduser(notmuchpath)

    alotconfig = None
    # read the first alot config file we find
    for configfilename in configfiles:
        if os.path.exists(configfilename):
            alotconfig = configfilename
            break  # use only the first

    try:
        settings.read_config(alotconfig)
        settings.read_notmuch_config(notmuchconfig)
    except (ConfigError, OSError, IOError) as e:
        sys.exit(e)

    # store options given by config swiches to the settingsManager:
    if args["colour-mode"]:
        settings.set("colourmode", args["colour-mode"])

    # get ourselves a database manager
    indexpath = settings.get_notmuch_setting("database", "path")
    indexpath = args["mailindex-path"] or indexpath
    dbman = DBManager(path=indexpath, ro=args["read-only"])

    # determine what to do
    try:
        if args.subCommand == "search":
            query = " ".join(args.subOptions.args)
            cmdstring = "search %s %s" % (args.subOptions.as_argparse_opts(), query)
        elif args.subCommand == "compose":
            cmdstring = "compose %s" % args.subOptions.as_argparse_opts()
            if args.subOptions.rest is not None:
                cmdstring += " " + args.subOptions.rest
        else:
            cmdstring = settings.get("initial_command")
    except CommandParseError as e:
        sys.exit(e)

    # set up and start interface
    UI(dbman, cmdstring)

    # run the exit hook
    exit_hook = settings.get_hook("exit")
    if exit_hook is not None:
        exit_hook()
Esempio n. 23
0
    # get ourselves a database manager
    indexpath = settings.get_notmuch_setting('database', 'path')
    indexpath = args['mailindex-path'] or indexpath
    dbman = DBManager(path=indexpath, ro=args['read-only'])

    # determine what to do
    try:
        if args.subCommand == 'search':
            query = ' '.join(args.subOptions.args)
            cmdstring = 'search %s %s' % (args.subOptions.as_argparse_opts(),
                                          query)
        elif args.subCommand == 'compose':
            cmdstring = 'compose %s' % args.subOptions.as_argparse_opts()
            if args.subOptions.rest is not None:
                cmdstring += ' ' + args.subOptions.rest
        else:
            cmdstring = settings.get('initial_command')
    except CommandParseError, e:
        sys.exit(e)

    # set up and start interface
    UI(dbman, cmdstring)

    # run the exit hook
    exit_hook = settings.get_hook('exit')
    if exit_hook is not None:
        exit_hook()

if __name__ == "__main__":
    main()
Esempio n. 24
0
    def apply(self, ui):
        ebuffer = ui.current_buffer
        if not self.envelope:
            self.envelope = ui.current_buffer.envelope

        #determine editable headers
        edit_headers = set(settings.get('edit_headers_whitelist'))
        if '*' in edit_headers:
            edit_headers = set(self.envelope.headers.keys())
        blacklist = set(settings.get('edit_headers_blacklist'))
        if '*' in blacklist:
            blacklist = set(self.envelope.headers.keys())
        edit_headers = edit_headers - blacklist
        logging.info('editable headers: %s' % edit_headers)

        def openEnvelopeFromTmpfile():
            # This parses the input from the tempfile.
            # we do this ourselves here because we want to be able to
            # just type utf-8 encoded stuff into the tempfile and let alot
            # worry about encodings.

            # get input
            # tempfile will be removed on buffer cleanup
            f = open(self.envelope.tmpfile.name)
            enc = settings.get('editor_writes_encoding')
            template = string_decode(f.read(), enc)
            f.close()

            # call post-edit translate hook
            translate = settings.get_hook('post_edit_translate')
            if translate:
                template = translate(template, ui=ui, dbm=ui.dbman)
            self.envelope.parse_template(template,
                                         only_body=self.edit_only_body)
            if self.openNew:
                ui.buffer_open(buffers.EnvelopeBuffer(ui, self.envelope))
            else:
                ebuffer.envelope = self.envelope
                ebuffer.rebuild()

        # decode header
        headertext = u''
        for key in edit_headers:
            vlist = self.envelope.get_all(key)
            if not vlist:
                # ensure editable headers are present in template
                vlist = ['']
            else:
                # remove to be edited lines from envelope
                del self.envelope[key]

            for value in vlist:
                # newlines (with surrounding spaces) by spaces in values
                value = value.strip()
                value = re.sub('[ \t\r\f\v]*\n[ \t\r\f\v]*', ' ', value)
                headertext += '%s: %s\n' % (key, value)

        # determine editable content
        bodytext = self.envelope.body
        if headertext:
            content = '%s\n%s' % (headertext, bodytext)
            self.edit_only_body = False
        else:
            content = bodytext
            self.edit_only_body = True

        # call pre-edit translate hook
        translate = settings.get_hook('pre_edit_translate')
        if translate:
            content = translate(content, ui=ui, dbm=ui.dbman)

        #write stuff to tempfile
        old_tmpfile = None
        if self.envelope.tmpfile:
            old_tmpfile = self.envelope.tmpfile
        self.envelope.tmpfile = tempfile.NamedTemporaryFile(delete=False,
                                                            prefix='alot.')
        self.envelope.tmpfile.write(content.encode('utf-8'))
        self.envelope.tmpfile.flush()
        self.envelope.tmpfile.close()
        if old_tmpfile:
            os.unlink(old_tmpfile.name)
        cmd = globals.EditCommand(self.envelope.tmpfile.name,
                                  on_success=openEnvelopeFromTmpfile,
                                  spawn=self.force_spawn,
                                  thread=self.force_spawn,
                                  refocus=self.refocus)
        ui.apply_command(cmd)
Esempio n. 25
0
    def apply(self, ui):
        # get message to forward if not given in constructor
        if not self.message:
            self.message = ui.current_buffer.get_selected_message()
        mail = self.message.get_email()

        envelope = Envelope()

        if self.inline:  # inline mode
            # set body text
            name, address = self.message.get_author()
            timestamp = self.message.get_date()
            qf = settings.get_hook('forward_prefix')
            if qf:
                quote = qf(name, address, timestamp, ui=ui, dbm=ui.dbman)
            else:
                quote = 'Forwarded message from %s (%s):\n' % (
                    name or address, timestamp)
            mailcontent = quote
            quotehook = settings.get_hook('text_quote')
            if quotehook:
                mailcontent += quotehook(self.message.accumulate_body())
            else:
                quote_prefix = settings.get('quote_prefix')
                for line in self.message.accumulate_body().splitlines():
                    mailcontent += quote_prefix + line + '\n'

            envelope.body = mailcontent

            for a in self.message.get_attachments():
                envelope.attach(a)

        else:  # attach original mode
            # attach original msg
            original_mail = Message()
            original_mail.set_type('message/rfc822')
            original_mail['Content-Disposition'] = 'attachment'
            original_mail.set_payload(email_as_string(mail))
            envelope.attach(Attachment(original_mail))

        # copy subject
        subject = decode_header(mail.get('Subject', ''))
        subject = 'Fwd: ' + subject
        forward_subject_hook = settings.get_hook('forward_subject')
        if forward_subject_hook:
            subject = forward_subject_hook(subject)
        else:
            fsp = settings.get('forward_subject_prefix')
            if not subject.startswith(('Fwd:', fsp)):
                subject = fsp + subject
        envelope.add('Subject', subject)

        # set From-header and sending account
        try:
            from_header, account = determine_sender(mail, 'reply')
        except AssertionError as e:
            ui.notify(e.message, priority='error')
            return
        envelope.add('From', from_header)

        # continue to compose
        ui.apply_command(ComposeCommand(envelope=envelope,
                                        spawn=self.force_spawn))