Ejemplo n.º 1
0
def newitemcopy(db, cl, nodeid, oldvalues):
    ''' Copy a message about new items to the dispatcher address.
    '''
    try:
        create_note = cl.generateCreateNote(nodeid)
    except AttributeError:
        create_note = generateCreateNote(db, cl, nodeid)

    try:
        dispatcher_email = getattr(db.config, 'DISPATCHER_EMAIL')
    except AttributeError:
        return

    try:
        msgids = cl.get(nodeid, 'messages')
    except KeyError:
        msgids = None

    if msgids:
        # send a copy to the dispatcher
        for msgid in msgids:
            try:
                cl.send_message(nodeid, msgid, create_note, [dispatcher_email])
            except roundupdb.MessageSendError as message:
                raise roundupdb.DetectorError(message)
    else:
        mailer = Mailer(db.config)
        subject = 'New %s%s' % (cl.classname, nodeid)
        mailer.standard_message([dispatcher_email], subject, create_note)
Ejemplo n.º 2
0
def notify (db, alarm, sensor, measurement, timestamp, is_lower) :
    sendto  = []
    for uid in db.user.getnodeids (retired = False) :
        adr = db.user.get (uid, 'address')
        if adr :
            sendto.append (adr)
    # do nothing if no addresses to notify
    if not adr :
        return
    _ = get_mail_translation (db).gettext
    overunder = _ (''"over")
    if is_lower :
        overunder = _ (''"under")
    dev = db.device.getnode (sensor.device)
    cname = sensor.name
    cadr  = sensor.adr
    dname = dev.name
    dadr  = dev.adr
    value = measurement.val
    threshold = alarm.val
    m = _ (msg) % locals ()
    mailer  = Mailer (db.config)
    subject = _ (''"Sensor alert")
    try :
        mailer.standard_message (sendto, subject, m)
    except MessageSendError, err :
        raise DetectorError, err
Ejemplo n.º 3
0
def send_non_roundup_mail(db, cls, issueid, msgid, sendto, cc=[], bcc=[]):
    """ Send mail to customer, don't use roundup change-email
        (nosymessage) mechanism -- so we can set different values and
        don't confuse the customer with roundup information.
    """
    cn = cls.classname
    msg = db.msg.getnode(msgid)

    issue = cls.getnode(issueid)
    title = issue.title or '%s message copy' % cn
    subject = '[%s%s] %s' % (cn, issueid, title)
    charset = getattr(db.config, 'EMAIL_CHARSET', 'utf-8')
    fromaddr = None
    if 'customer' in cls.properties:
        customer = db.customer.getnode(issue.customer)
        if 'type' in cls.properties and 'rmafrom' in db.customer.properties:
            type = db.sup_type.get(issue.type, 'name')
            fromaddr = getattr(customer, fromprops_by_type.get(type))
        if not fromaddr:
            fromaddr = customer.fromaddress
    if not fromaddr:
        fromaddr = db.config.TRACKER_EMAIL
    user = db.user.getnode(msg.author)
    authname = user.realname or user.username or ''
    author = (authname, fromaddr)

    m = ['']
    m.append(msg.content or '')
    body = unicode('\n'.join(m), 'utf-8').encode(charset)

    mailer = Mailer(db.config)
    message = mailer.get_standard_message(multipart=bool(msg.files))
    mailer.set_message_attributes(message, sendto, subject, author)
    message['Message-Id'] = msg.messageid
    if cc:
        message['Cc'] = ', '.join(cc)
    if msg.inreplyto:
        message['In-Reply-To'] = msg.inreplyto
    if msg.files:
        part = mailer.get_text_message()
        part.set_payload(body, charset)
        message.attach(part)
    else:
        message.set_payload(body, charset)
    for f in msg.files:
        file = db.file.getnode(f)
        if file.type == 'text/plain':
            part = mailer.get_text_message()
            part.set_payload(file.content)
        else:
            type = file.type
            if not type:
                type = mimetypes.guess_type(file.name)[0]
            if type is None:
                type = 'application/octet-stream'
            main, sub = type.split('/')
            part = MIMENonMultipart(main, sub)
            part.set_payload(file.content)
        cd = 'Content-Disposition'
        part[cd] = 'attachment;\n filename="%s"' % file.name
        message.attach(part)
    mailer.smtp_send(sendto + cc + bcc, message.as_string())
Ejemplo n.º 4
0
    def send_message(self,
                     issueid,
                     msgid,
                     note,
                     sendto,
                     from_address=None,
                     bcc_sendto=[],
                     subject=None,
                     crypt=False,
                     add_headers={},
                     authid=None):
        '''Actually send the nominated message from this issue to the sendto
           recipients, with the note appended. It's possible to add
           headers to the message with the add_headers variable.
        '''
        users = self.db.user
        messages = self.db.msg
        files = self.db.file

        if msgid is None:
            inreplyto = None
            messageid = None
        else:
            inreplyto = messages.get(msgid, 'inreplyto')
            messageid = messages.get(msgid, 'messageid')

        # make up a messageid if there isn't one (web edit)
        if not messageid:
            # this is an old message that didn't get a messageid, so
            # create one
            messageid = "<%s.%s.%s%s@%s>" % (
                time.time(), b2s(base64.b32encode(random_.token_bytes(10))),
                self.classname, issueid, self.db.config['MAIL_DOMAIN'])
            if msgid is not None:
                messages.set(msgid, messageid=messageid)

        # compose title
        cn = self.classname
        title = self.get(issueid, 'title') or '%s message copy' % cn

        # figure author information
        if authid:
            pass
        elif msgid:
            authid = messages.get(msgid, 'author')
        else:
            authid = self.db.getuid()
        authname = users.get(authid, 'realname')
        if not authname:
            authname = users.get(authid, 'username', '')
        authaddr = users.get(authid, 'address', '')

        if authaddr and self.db.config.MAIL_ADD_AUTHOREMAIL:
            authaddr = " <%s>" % formataddr(('', authaddr))
        elif authaddr:
            authaddr = ""

        # make the message body
        m = ['']

        # put in roundup's signature
        if self.db.config.EMAIL_SIGNATURE_POSITION == 'top':
            m.append(self.email_signature(issueid, msgid))

        # add author information
        if authid and self.db.config.MAIL_ADD_AUTHORINFO:
            if msgid and len(self.get(issueid, 'messages')) == 1:
                m.append(
                    _("New submission from %(authname)s%(authaddr)s:") %
                    locals())
            elif msgid:
                m.append(
                    _("%(authname)s%(authaddr)s added the comment:") %
                    locals())
            else:
                m.append(_("Change by %(authname)s%(authaddr)s:") % locals())
            m.append('')

        # add the content
        if msgid is not None:
            m.append(messages.get(msgid, 'content', ''))

        # get the files for this message
        message_files = []
        if msgid:
            for fileid in messages.get(msgid, 'files'):
                # check the attachment size
                filesize = self.db.filesize('file', fileid, None)
                if filesize <= self.db.config.NOSY_MAX_ATTACHMENT_SIZE:
                    message_files.append(fileid)
                else:
                    base = self.db.config.TRACKER_WEB
                    link = "".join((base, files.classname, fileid))
                    filename = files.get(fileid, 'name')
                    m.append(
                        _("File '%(filename)s' not attached - "
                          "you can download it from %(link)s.") % locals())

        # add the change note
        if note:
            m.append(note)

        # put in roundup's signature
        if self.db.config.EMAIL_SIGNATURE_POSITION == 'bottom':
            m.append(self.email_signature(issueid, msgid))

        # figure the encoding
        charset = getattr(self.db.config, 'EMAIL_CHARSET', 'utf-8')

        # construct the content and convert to unicode object
        body = s2u('\n'.join(m))

        # make sure the To line is always the same (for testing mostly)
        sendto.sort()

        # make sure we have a from address
        if from_address is None:
            from_address = self.db.config.TRACKER_EMAIL

        # additional bit for after the From: "name"
        from_tag = getattr(self.db.config, 'EMAIL_FROM_TAG', '')
        if from_tag:
            from_tag = ' ' + from_tag

        if subject is None:
            subject = '[%s%s] %s' % (cn, issueid, title)

        author = (authname + from_tag, from_address)

        # send an individual message per recipient?
        if self.db.config.NOSY_EMAIL_SENDING != 'single':
            sendto = [[address] for address in sendto]
        else:
            sendto = [sendto]

        # tracker sender info
        tracker_name = s2u(self.db.config.TRACKER_NAME)
        tracker_name = nice_sender_header(tracker_name, from_address, charset)

        # now send one or more messages
        # TODO: I believe we have to create a new message each time as we
        # can't fiddle the recipients in the message ... worth testing
        # and/or fixing some day
        first = True
        for sendto in sendto:
            # create the message
            mailer = Mailer(self.db.config)

            message = mailer.get_standard_message(multipart=message_files)

            # set reply-to as requested by config option
            # TRACKER_REPLYTO_ADDRESS
            replyto_config = self.db.config.TRACKER_REPLYTO_ADDRESS
            if replyto_config:
                if replyto_config == "AUTHOR":
                    # note that authaddr at this point is already
                    # surrounded by < >, so get the original address
                    # from the db as nice_send_header adds < >
                    replyto_addr = nice_sender_header(
                        authname, users.get(authid, 'address', ''), charset)
                else:
                    replyto_addr = replyto_config
            else:
                replyto_addr = tracker_name
            message['Reply-To'] = replyto_addr

            # message ids
            if messageid:
                message['Message-Id'] = messageid
            if inreplyto:
                message['In-Reply-To'] = inreplyto

            # Generate a header for each link or multilink to
            # a class that has a name attribute
            for propname, prop in self.getprops().items():
                if not isinstance(prop, (hyperdb.Link, hyperdb.Multilink)):
                    continue
                cl = self.db.getclass(prop.classname)
                label = None
                if 'name' in cl.getprops():
                    label = 'name'
                if prop.msg_header_property in cl.getprops():
                    label = prop.msg_header_property
                if prop.msg_header_property == "":
                    # if msg_header_property is set to empty string
                    # suppress the header entirely. You can't use
                    # 'msg_header_property == None'. None is the
                    # default value.
                    label = None
                if not label:
                    continue
                if isinstance(prop, hyperdb.Link):
                    value = self.get(issueid, propname)
                    if value is None:
                        continue
                    values = [value]
                else:
                    values = self.get(issueid, propname)
                    if not values:
                        continue
                values = [cl.get(v, label) for v in values]
                values = ', '.join(values)
                header = "X-Roundup-%s-%s" % (self.classname, propname)
                try:
                    values.encode('ascii')
                    message[header] = values
                except UnicodeError:
                    message[header] = Header(values, charset)

            # Add header for main id number to make filtering
            # email easier than extracting from subject line.
            header = "X-Roundup-%s-Id" % (self.classname)
            values = issueid
            try:
                values.encode('ascii')
                message[header] = values
            except UnicodeError:
                message[header] = Header(values, charset)
            # Generate additional headers
            for k in add_headers:
                v = add_headers[k]
                try:
                    v.encode('ascii')
                    message[k] = v
                except UnicodeError:
                    message[k] = Header(v, charset)

            if not inreplyto:
                # Default the reply to the first message
                msgs = self.get(issueid, 'messages')
                # Assume messages are sorted by increasing message number here
                # If the issue is just being created, and the submitter didn't
                # provide a message, then msgs will be empty.
                if msgs and msgs[0] != msgid:
                    inreplyto = messages.get(msgs[0], 'messageid')
                    if inreplyto:
                        message['In-Reply-To'] = inreplyto

            # attach files
            if message_files:
                # first up the text as a part
                part = mailer.get_standard_message()
                part.set_payload(body, part.get_charset())
                message.attach(part)

                for fileid in message_files:
                    name = files.get(fileid, 'name')
                    mime_type = (files.get(fileid, 'type')
                                 or mimetypes.guess_type(name)[0]
                                 or 'application/octet-stream')
                    if mime_type == 'text/plain':
                        content = files.get(fileid, 'content')
                        part = MIMEText('')
                        del part['Content-Transfer-Encoding']
                        try:
                            enc = content.encode('ascii')
                            part = mailer.get_text_message('us-ascii')
                            part.set_payload(enc)
                        except UnicodeError:
                            # the content cannot be 7bit-encoded.
                            # use quoted printable
                            # XXX stuffed if we know the charset though :(
                            part = mailer.get_text_message('utf-8')
                            part.set_payload(content, part.get_charset())
                    elif mime_type == 'message/rfc822':
                        content = files.get(fileid, 'content')
                        main, sub = mime_type.split('/')
                        p = FeedParser()
                        p.feed(content)
                        part = MIMEBase(main, sub)
                        part.set_payload([p.close()])
                    else:
                        # some other type, so encode it
                        content = files.get(fileid, 'binary_content')
                        main, sub = mime_type.split('/')
                        part = MIMEBase(main, sub)
                        part.set_payload(content)
                        encoders.encode_base64(part)
                    cd = 'Content-Disposition'
                    part[cd] = 'attachment;\n filename="%s"' % name
                    message.attach(part)

            else:
                message.set_payload(body, message.get_charset())

            if crypt:
                send_msg = self.encrypt_to(message, sendto)
            else:
                send_msg = message
            mailer.set_message_attributes(send_msg, sendto, subject, author)
            if crypt:
                send_msg['Message-Id'] = message['Message-Id']
                send_msg['Reply-To'] = message['Reply-To']
                if message.get('In-Reply-To'):
                    send_msg['In-Reply-To'] = message['In-Reply-To']

            if sendto:
                mailer.smtp_send(sendto, send_msg.as_string())
            if first:
                if crypt:
                    # send individual bcc mails, otherwise receivers can
                    # deduce bcc recipients from keys in message
                    for bcc in bcc_sendto:
                        send_msg = self.encrypt_to(message, [bcc])
                        send_msg['Message-Id'] = message['Message-Id']
                        send_msg['Reply-To'] = message['Reply-To']
                        if message.get('In-Reply-To'):
                            send_msg['In-Reply-To'] = message['In-Reply-To']
                        mailer.smtp_send([bcc], send_msg.as_string())
                elif bcc_sendto:
                    mailer.smtp_send(bcc_sendto, send_msg.as_string())
            first = False
Ejemplo n.º 5
0
    def send_message(self, issueid, msgid, note, sendto, from_address=None,
            bcc_sendto=[], subject=None, crypt=False):
        '''Actually send the nominated message from this issue to the sendto
           recipients, with the note appended.
        '''
        users = self.db.user
        messages = self.db.msg
        files = self.db.file

        if msgid is None:
            inreplyto = None
            messageid = None
        else:
            inreplyto = messages.get(msgid, 'inreplyto')
            messageid = messages.get(msgid, 'messageid')

        # make up a messageid if there isn't one (web edit)
        if not messageid:
            # this is an old message that didn't get a messageid, so
            # create one
            messageid = "<%s.%s.%s%s@%s>"%(time.time(), random.random(),
                                           self.classname, issueid,
                                           self.db.config.MAIL_DOMAIN)
            if msgid is not None:
                messages.set(msgid, messageid=messageid)

        # compose title
        cn = self.classname
        title = self.get(issueid, 'title') or '%s message copy'%cn

        # figure author information
        if msgid:
            authid = messages.get(msgid, 'author')
        else:
            authid = self.db.getuid()
        authname = users.get(authid, 'realname')
        if not authname:
            authname = users.get(authid, 'username', '')
        authaddr = users.get(authid, 'address', '')

        if authaddr and self.db.config.MAIL_ADD_AUTHOREMAIL:
            authaddr = " <%s>" % formataddr( ('',authaddr) )
        elif authaddr:
            authaddr = ""

        # make the message body
        m = ['']

        # put in roundup's signature
        if self.db.config.EMAIL_SIGNATURE_POSITION == 'top':
            m.append(self.email_signature(issueid, msgid))

        # add author information
        if authid and self.db.config.MAIL_ADD_AUTHORINFO:
            if msgid and len(self.get(issueid, 'messages')) == 1:
                m.append(_("New submission from %(authname)s%(authaddr)s:")
                    % locals())
            elif msgid:
                m.append(_("%(authname)s%(authaddr)s added the comment:")
                    % locals())
            else:
                m.append(_("Change by %(authname)s%(authaddr)s:") % locals())
            m.append('')

        # add the content
        if msgid is not None:
            m.append(messages.get(msgid, 'content', ''))

        # get the files for this message
        message_files = []
        if msgid :
            for fileid in messages.get(msgid, 'files') :
                # check the attachment size
                filesize = self.db.filesize('file', fileid, None)
                if filesize <= self.db.config.NOSY_MAX_ATTACHMENT_SIZE:
                    message_files.append(fileid)
                else:
                    base = self.db.config.TRACKER_WEB
                    link = "".join((base, files.classname, fileid))
                    filename = files.get(fileid, 'name')
                    m.append(_("File '%(filename)s' not attached - "
                        "you can download it from %(link)s.") % locals())

        # add the change note
        if note:
            m.append(note)

        # put in roundup's signature
        if self.db.config.EMAIL_SIGNATURE_POSITION == 'bottom':
            m.append(self.email_signature(issueid, msgid))

        # figure the encoding
        charset = getattr(self.db.config, 'EMAIL_CHARSET', 'utf-8')

        # construct the content and convert to unicode object
        body = unicode('\n'.join(m), 'utf-8').encode(charset)

        # make sure the To line is always the same (for testing mostly)
        sendto.sort()

        # make sure we have a from address
        if from_address is None:
            from_address = self.db.config.TRACKER_EMAIL

        # additional bit for after the From: "name"
        from_tag = getattr(self.db.config, 'EMAIL_FROM_TAG', '')
        if from_tag:
            from_tag = ' ' + from_tag

        if subject is None:
            subject = '[%s%s] %s'%(cn, issueid, title)

        author = (authname + from_tag, from_address)

        # send an individual message per recipient?
        if self.db.config.NOSY_EMAIL_SENDING != 'single':
            sendto = [[address] for address in sendto]
        else:
            sendto = [sendto]

        # tracker sender info
        tracker_name = unicode(self.db.config.TRACKER_NAME, 'utf-8')
        tracker_name = nice_sender_header(tracker_name, from_address,
            charset)

        # now send one or more messages
        # TODO: I believe we have to create a new message each time as we
        # can't fiddle the recipients in the message ... worth testing
        # and/or fixing some day
        first = True
        for sendto in sendto:
            # create the message
            mailer = Mailer(self.db.config)

            message = mailer.get_standard_message(multipart=message_files)

            # set reply-to as requested by config option TRACKER_REPLYTO_ADDRESS
            replyto_config = self.db.config.TRACKER_REPLYTO_ADDRESS
            if replyto_config:
                if replyto_config == "AUTHOR":
                    # note that authaddr at this point is already surrounded by < >, so
                    # get the original address from the db as nice_send_header adds < >
                    replyto_addr = nice_sender_header(authname, users.get(authid, 'address', ''), charset)
                else:
                    replyto_addr = replyto_config
            else:
                replyto_addr = tracker_name
            message['Reply-To'] = replyto_addr

            # message ids
            if messageid:
                message['Message-Id'] = messageid
            if inreplyto:
                message['In-Reply-To'] = inreplyto

            # Generate a header for each link or multilink to
            # a class that has a name attribute
            for propname, prop in self.getprops().items():
                if not isinstance(prop, (hyperdb.Link, hyperdb.Multilink)):
                    continue
                cl = self.db.getclass(prop.classname)
                label = None
                if 'name' in cl.getprops():
                    label = 'name'
                if prop.msg_header_property in cl.getprops():
                    label = prop.msg_header_property
                if prop.msg_header_property == "":
                    # if msg_header_property is set to empty string
                    # suppress the header entirely. You can't use
                    # 'msg_header_property == None'. None is the
                    # default value.
                    label = None
                if not label:
                    continue
                if isinstance(prop, hyperdb.Link):
                    value = self.get(issueid, propname)
                    if value is None:
                        continue
                    values = [value]
                else:
                    values = self.get(issueid, propname)
                    if not values:
                        continue
                values = [cl.get(v, label) for v in values]
                values = ', '.join(values)
                header = "X-Roundup-%s-%s"%(self.classname, propname)
                try:
                    message[header] = values.encode('ascii')
                except UnicodeError:
                    message[header] = Header(values, charset)

            if not inreplyto:
                # Default the reply to the first message
                msgs = self.get(issueid, 'messages')
                # Assume messages are sorted by increasing message number here
                # If the issue is just being created, and the submitter didn't
                # provide a message, then msgs will be empty.
                if msgs and msgs[0] != msgid:
                    inreplyto = messages.get(msgs[0], 'messageid')
                    if inreplyto:
                        message['In-Reply-To'] = inreplyto

            # attach files
            if message_files:
                # first up the text as a part
                part = MIMEText(body)
                part.set_charset(charset)
                encode_quopri(part)
                message.attach(part)

                for fileid in message_files:
                    name = files.get(fileid, 'name')
                    mime_type = files.get(fileid, 'type')
                    content = files.get(fileid, 'content')
                    if mime_type == 'text/plain':
                        try:
                            content.decode('ascii')
                        except UnicodeError:
                            # the content cannot be 7bit-encoded.
                            # use quoted printable
                            # XXX stuffed if we know the charset though :(
                            part = MIMEText(content)
                            encode_quopri(part)
                        else:
                            part = MIMEText(content)
                            part['Content-Transfer-Encoding'] = '7bit'
                    elif mime_type == 'message/rfc822':
                        main, sub = mime_type.split('/')
                        p = FeedParser()
                        p.feed(content)
                        part = MIMEBase(main, sub)
                        part.set_payload([p.close()])
                    else:
                        # some other type, so encode it
                        if not mime_type:
                            # this should have been done when the file was saved
                            mime_type = mimetypes.guess_type(name)[0]
                        if mime_type is None:
                            mime_type = 'application/octet-stream'
                        main, sub = mime_type.split('/')
                        part = MIMEBase(main, sub)
                        part.set_payload(content)
                        Encoders.encode_base64(part)
                    cd = 'Content-Disposition'
                    part[cd] = 'attachment;\n filename="%s"'%name
                    message.attach(part)

            else:
                message.set_payload(body)
                encode_quopri(message)

            if crypt:
                send_msg = self.encrypt_to (message, sendto)
            else:
                send_msg = message
            mailer.set_message_attributes(send_msg, sendto, subject, author)
            if crypt:
                send_msg ['Message-Id'] = message ['Message-Id']
                send_msg ['Reply-To'] = message ['Reply-To']
                if message.get ('In-Reply-To'):
                    send_msg ['In-Reply-To'] = message ['In-Reply-To']

            mailer.smtp_send(sendto, send_msg.as_string())
            if first:
                if crypt:
                    # send individual bcc mails, otherwise receivers can
                    # deduce bcc recipients from keys in message
                    for bcc in bcc_sendto:
                        send_msg = self.encrypt_to (message, [bcc])
                        send_msg ['Message-Id'] = message ['Message-Id']
                        send_msg ['Reply-To'] = message ['Reply-To']
                        if message.get ('In-Reply-To'):
                            send_msg ['In-Reply-To'] = message ['In-Reply-To']
                        mailer.smtp_send([bcc], send_msg.as_string())
                elif bcc_sendto:
                    mailer.smtp_send(bcc_sendto, send_msg.as_string())
            first = False
Ejemplo n.º 6
0
    def send_message(self,
                     nodeid,
                     msgid,
                     note,
                     sendto,
                     from_address=None,
                     bcc_sendto=[]):
        '''Actually send the nominated message from this node to the sendto
           recipients, with the note appended.
        '''
        users = self.db.user
        messages = self.db.msg
        files = self.db.file

        if msgid is None:
            inreplyto = None
            messageid = None
        else:
            inreplyto = messages.get(msgid, 'inreplyto')
            messageid = messages.get(msgid, 'messageid')

        # make up a messageid if there isn't one (web edit)
        if not messageid:
            # this is an old message that didn't get a messageid, so
            # create one
            messageid = "<%s.%s.%s%s@%s>" % (time.time(), random.random(),
                                             self.classname, nodeid,
                                             self.db.config.MAIL_DOMAIN)
            if msgid is not None:
                messages.set(msgid, messageid=messageid)

        # compose title
        cn = self.classname
        title = self.get(nodeid, 'title') or '%s message copy' % cn

        # figure author information
        if msgid:
            authid = messages.get(msgid, 'author')
        else:
            authid = self.db.getuid()
        authname = users.get(authid, 'realname')
        if not authname:
            authname = users.get(authid, 'username', '')
        authaddr = users.get(authid, 'address', '')

        if authaddr and self.db.config.MAIL_ADD_AUTHOREMAIL:
            authaddr = " <%s>" % straddr(('', authaddr))
        elif authaddr:
            authaddr = ""

        # make the message body
        m = ['']

        # put in roundup's signature
        if self.db.config.EMAIL_SIGNATURE_POSITION == 'top':
            m.append(self.email_signature(nodeid, msgid))

        # add author information
        if authid and self.db.config.MAIL_ADD_AUTHORINFO:
            if msgid and len(self.get(nodeid, 'messages')) == 1:
                m.append(
                    _("New submission from %(authname)s%(authaddr)s:") %
                    locals())
            elif msgid:
                m.append(
                    _("%(authname)s%(authaddr)s added the comment:") %
                    locals())
            else:
                m.append(_("Change by %(authname)s%(authaddr)s:") % locals())
            m.append('')

        # add the content
        if msgid is not None:
            m.append(messages.get(msgid, 'content', ''))

        # get the files for this message
        message_files = []
        if msgid:
            for fileid in messages.get(msgid, 'files'):
                # check the attachment size
                filename = self.db.filename('file', fileid, None)
                filesize = os.path.getsize(filename)
                if filesize <= self.db.config.NOSY_MAX_ATTACHMENT_SIZE:
                    message_files.append(fileid)
                else:
                    base = self.db.config.TRACKER_WEB
                    link = "".join((base, files.classname, fileid))
                    filename = files.get(fileid, 'name')
                    m.append(
                        _("File '%(filename)s' not attached - "
                          "you can download it from %(link)s.") % locals())

        # add the change note
        if note:
            m.append(note)

        # put in roundup's signature
        if self.db.config.EMAIL_SIGNATURE_POSITION == 'bottom':
            m.append(self.email_signature(nodeid, msgid))

        # encode the content as quoted-printable
        charset = getattr(self.db.config, 'EMAIL_CHARSET', 'utf-8')
        m = '\n'.join(m)
        if charset != 'utf-8':
            m = unicode(m, 'utf-8').encode(charset)
        content = cStringIO.StringIO(m)
        content_encoded = cStringIO.StringIO()
        quopri.encode(content, content_encoded, 0)
        content_encoded = content_encoded.getvalue()

        # make sure the To line is always the same (for testing mostly)
        sendto.sort()

        # make sure we have a from address
        if from_address is None:
            from_address = self.db.config.TRACKER_EMAIL

        # additional bit for after the From: "name"
        from_tag = getattr(self.db.config, 'EMAIL_FROM_TAG', '')
        if from_tag:
            from_tag = ' ' + from_tag

        subject = '[%s%s] %s' % (cn, nodeid, title)
        author = (authname + from_tag, from_address)

        # send an individual message per recipient?
        if self.db.config.NOSY_EMAIL_SENDING != 'single':
            sendto = [[address] for address in sendto]
        else:
            sendto = [sendto]

        # now send one or more messages
        # TODO: I believe we have to create a new message each time as we
        # can't fiddle the recipients in the message ... worth testing
        # and/or fixing some day
        first = True
        for sendto in sendto:
            # create the message
            mailer = Mailer(self.db.config)
            message, writer = mailer.get_standard_message(
                sendto, subject, author)

            # set reply-to to the tracker
            tracker_name = self.db.config.TRACKER_NAME
            if charset != 'utf-8':
                tracker = unicode(tracker_name, 'utf-8').encode(charset)
            tracker_name = encode_header(tracker_name, charset)
            writer.addheader('Reply-To', straddr((tracker_name, from_address)))

            # message ids
            if messageid:
                writer.addheader('Message-Id', messageid)
            if inreplyto:
                writer.addheader('In-Reply-To', inreplyto)

            # Generate a header for each link or multilink to
            # a class that has a name attribute
            for propname, prop in self.getprops().items():
                if not isinstance(prop, (hyperdb.Link, hyperdb.Multilink)):
                    continue
                cl = self.db.getclass(prop.classname)
                if not 'name' in cl.getprops():
                    continue
                if isinstance(prop, hyperdb.Link):
                    value = self.get(nodeid, propname)
                    if value is None:
                        continue
                    values = [value]
                else:
                    values = self.get(nodeid, propname)
                    if not values:
                        continue
                values = [cl.get(v, 'name') for v in values]
                values = ', '.join(values)
                writer.addheader(
                    "X-Roundup-%s-%s" % (self.classname, propname), values)
            if not inreplyto:
                # Default the reply to the first message
                msgs = self.get(nodeid, 'messages')
                # Assume messages are sorted by increasing message number here
                if msgs[0] != nodeid:
                    inreplyto = messages.get(msgs[0], 'messageid')
                    if inreplyto:
                        writer.addheader('In-Reply-To', inreplyto)

            # attach files
            if message_files:
                part = writer.startmultipartbody('mixed')
                part = writer.nextpart()
                part.addheader('Content-Transfer-Encoding', 'quoted-printable')
                body = part.startbody('text/plain; charset=%s' % charset)
                body.write(content_encoded)
                for fileid in message_files:
                    name = files.get(fileid, 'name')
                    mime_type = files.get(fileid, 'type')
                    content = files.get(fileid, 'content')
                    part = writer.nextpart()
                    if mime_type == 'text/plain':
                        part.addheader('Content-Disposition',
                                       'attachment;\n filename="%s"' % name)
                        try:
                            content.decode('ascii')
                        except UnicodeError:
                            # the content cannot be 7bit-encoded.
                            # use quoted printable
                            part.addheader('Content-Transfer-Encoding',
                                           'quoted-printable')
                            body = part.startbody('text/plain')
                            body.write(quopri.encodestring(content))
                        else:
                            part.addheader('Content-Transfer-Encoding', '7bit')
                            body = part.startbody('text/plain')
                            body.write(content)
                    else:
                        # some other type, so encode it
                        if not mime_type:
                            # this should have been done when the file was saved
                            mime_type = mimetypes.guess_type(name)[0]
                        if mime_type is None:
                            mime_type = 'application/octet-stream'
                        part.addheader('Content-Disposition',
                                       'attachment;\n filename="%s"' % name)
                        part.addheader('Content-Transfer-Encoding', 'base64')
                        body = part.startbody(mime_type)
                        body.write(base64.encodestring(content))
                writer.lastpart()
            else:
                writer.addheader('Content-Transfer-Encoding',
                                 'quoted-printable')
                body = writer.startbody('text/plain; charset=%s' % charset)
                body.write(content_encoded)

            if first:
                mailer.smtp_send(sendto + bcc_sendto, message)
            else:
                mailer.smtp_send(sendto, message)
            first = False
Ejemplo n.º 7
0
    def send_message(self, nodeid, msgid, note, sendto, from_address=None,
            bcc_sendto=[]):
        '''Actually send the nominated message from this node to the sendto
           recipients, with the note appended.
        '''
        users = self.db.user
        messages = self.db.msg
        files = self.db.file

        if msgid is None:
            inreplyto = None
            messageid = None
        else:
            inreplyto = messages.get(msgid, 'inreplyto')
            messageid = messages.get(msgid, 'messageid')

        # make up a messageid if there isn't one (web edit)
        if not messageid:
            # this is an old message that didn't get a messageid, so
            # create one
            messageid = "<%s.%s.%s%s@%s>"%(time.time(), random.random(),
                                           self.classname, nodeid,
                                           self.db.config.MAIL_DOMAIN)
            if msgid is not None:
                messages.set(msgid, messageid=messageid)

        # compose title
        cn = self.classname
        title = self.get(nodeid, 'title') or '%s message copy'%cn

        # figure author information
        if msgid:
            authid = messages.get(msgid, 'author')
        else:
            authid = self.db.getuid()
        authname = users.get(authid, 'realname')
        if not authname:
            authname = users.get(authid, 'username', '')
        authaddr = users.get(authid, 'address', '')

        if authaddr and self.db.config.MAIL_ADD_AUTHOREMAIL:
            authaddr = " <%s>" % straddr( ('',authaddr) )
        elif authaddr:
            authaddr = ""

        # make the message body
        m = ['']

        # put in roundup's signature
        if self.db.config.EMAIL_SIGNATURE_POSITION == 'top':
            m.append(self.email_signature(nodeid, msgid))

        # add author information
        if authid and self.db.config.MAIL_ADD_AUTHORINFO:
            if msgid and len(self.get(nodeid, 'messages')) == 1:
                m.append(_("New submission from %(authname)s%(authaddr)s:")
                    % locals())
            elif msgid:
                m.append(_("%(authname)s%(authaddr)s added the comment:")
                    % locals())
            else:
                m.append(_("Change by %(authname)s%(authaddr)s:") % locals())
            m.append('')

        # add the content
        if msgid is not None:
            m.append(messages.get(msgid, 'content', ''))

        # get the files for this message
        message_files = []
        if msgid :
            for fileid in messages.get(msgid, 'files') :
                # check the attachment size
                filename = self.db.filename('file', fileid, None)
                filesize = os.path.getsize(filename)
                if filesize <= self.db.config.NOSY_MAX_ATTACHMENT_SIZE:
                    message_files.append(fileid)
                else:
                    base = self.db.config.TRACKER_WEB
                    link = "".join((base, files.classname, fileid))
                    filename = files.get(fileid, 'name')
                    m.append(_("File '%(filename)s' not attached - "
                        "you can download it from %(link)s.") % locals())

        # add the change note
        if note:
            m.append(note)

        # put in roundup's signature
        if self.db.config.EMAIL_SIGNATURE_POSITION == 'bottom':
            m.append(self.email_signature(nodeid, msgid))

        # encode the content as quoted-printable
        charset = getattr(self.db.config, 'EMAIL_CHARSET', 'utf-8')
        m = '\n'.join(m)
        if charset != 'utf-8':
            m = unicode(m, 'utf-8').encode(charset)
        content = cStringIO.StringIO(m)
        content_encoded = cStringIO.StringIO()
        quopri.encode(content, content_encoded, 0)
        content_encoded = content_encoded.getvalue()

        # make sure the To line is always the same (for testing mostly)
        sendto.sort()

        # make sure we have a from address
        if from_address is None:
            from_address = self.db.config.TRACKER_EMAIL

        # additional bit for after the From: "name"
        from_tag = getattr(self.db.config, 'EMAIL_FROM_TAG', '')
        if from_tag:
            from_tag = ' ' + from_tag

        subject = '[%s%s] %s'%(cn, nodeid, title)
        author = (authname + from_tag, from_address)

        # send an individual message per recipient?
        if self.db.config.NOSY_EMAIL_SENDING != 'single':
            sendto = [[address] for address in sendto]
        else:
            sendto = [sendto]

        # now send one or more messages
        # TODO: I believe we have to create a new message each time as we
        # can't fiddle the recipients in the message ... worth testing
        # and/or fixing some day
        first = True
        for sendto in sendto:
            # create the message
            mailer = Mailer(self.db.config)
            message, writer = mailer.get_standard_message(sendto, subject,
                author)

            # set reply-to to the tracker
            tracker_name = self.db.config.TRACKER_NAME
            if charset != 'utf-8':
                tracker = unicode(tracker_name, 'utf-8').encode(charset)
            tracker_name = encode_header(tracker_name, charset)
            writer.addheader('Reply-To', straddr((tracker_name, from_address)))

            # message ids
            if messageid:
                writer.addheader('Message-Id', messageid)
            if inreplyto:
                writer.addheader('In-Reply-To', inreplyto)

            # Generate a header for each link or multilink to
            # a class that has a name attribute
            for propname, prop in self.getprops().items():
                if not isinstance(prop, (hyperdb.Link, hyperdb.Multilink)):
                    continue
                cl = self.db.getclass(prop.classname)
                if not 'name' in cl.getprops():
                    continue
                if isinstance(prop, hyperdb.Link):
                    value = self.get(nodeid, propname)
                    if value is None:
                        continue
                    values = [value]
                else:
                    values = self.get(nodeid, propname)
                    if not values:
                        continue
                values = [cl.get(v, 'name') for v in values]
                values = ', '.join(values)
                writer.addheader("X-Roundup-%s-%s" % (self.classname, propname),
                                 values)
            if not inreplyto:
                # Default the reply to the first message
                msgs = self.get(nodeid, 'messages')
                # Assume messages are sorted by increasing message number here
                if msgs[0] != nodeid:
                    inreplyto = messages.get(msgs[0], 'messageid')
                    if inreplyto:
                        writer.addheader('In-Reply-To', inreplyto)

            # attach files
            if message_files:
                part = writer.startmultipartbody('mixed')
                part = writer.nextpart()
                part.addheader('Content-Transfer-Encoding', 'quoted-printable')
                body = part.startbody('text/plain; charset=%s'%charset)
                body.write(content_encoded)
                for fileid in message_files:
                    name = files.get(fileid, 'name')
                    mime_type = files.get(fileid, 'type')
                    content = files.get(fileid, 'content')
                    part = writer.nextpart()
                    if mime_type == 'text/plain':
                        part.addheader('Content-Disposition',
                            'attachment;\n filename="%s"'%name)
                        try:
                            content.decode('ascii')
                        except UnicodeError:
                            # the content cannot be 7bit-encoded.
                            # use quoted printable
                            part.addheader('Content-Transfer-Encoding',
                                'quoted-printable')
                            body = part.startbody('text/plain')
                            body.write(quopri.encodestring(content))
                        else:
                            part.addheader('Content-Transfer-Encoding', '7bit')
                            body = part.startbody('text/plain')
                            body.write(content)
                    else:
                        # some other type, so encode it
                        if not mime_type:
                            # this should have been done when the file was saved
                            mime_type = mimetypes.guess_type(name)[0]
                        if mime_type is None:
                            mime_type = 'application/octet-stream'
                        part.addheader('Content-Disposition',
                            'attachment;\n filename="%s"'%name)
                        part.addheader('Content-Transfer-Encoding', 'base64')
                        body = part.startbody(mime_type)
                        body.write(base64.encodestring(content))
                writer.lastpart()
            else:
                writer.addheader('Content-Transfer-Encoding',
                    'quoted-printable')
                body = writer.startbody('text/plain; charset=%s'%charset)
                body.write(content_encoded)

            if first:
                mailer.smtp_send(sendto + bcc_sendto, message)
            else:
                mailer.smtp_send(sendto, message)
            first = False
Ejemplo n.º 8
0
        create_note = cl.generateCreateNote(nodeid)
    except AttributeError:
        create_note = generateCreateNote(db, cl, nodeid)

    try:
        dispatcher_email = getattr(db.config, 'DISPATCHER_EMAIL')
    except AttributeError:
        return

    try:
        msgids = cl.get(nodeid, 'messages')
    except KeyError:
        msgids = None

    if msgids:
        # send a copy to the dispatcher
        for msgid in msgids:
            try:
                cl.send_message(nodeid, msgid, create_note, [dispatcher_email])
            except roundupdb.MessageSendError, message:
                raise roundupdb.DetectorError, message
    else:
        mailer = Mailer(db.config)
        subject = 'New %s%s' % (cl.classname, nodeid)
        mailer.standard_message([dispatcher_email], subject, create_note)

def init(db):
    for classname in db.getclasses():
        cl = db.getclass(classname)
        cl.react('create', newitemcopy)
def topdesk_integration(db, cl, nodeid, oldvalues):
    """Perform roundup-TOPDesk integration

    https://www.s3it.uzh.ch/help/issue630

    If:

    * Body of the email starts with
      `Forwarding Incident I-[0-9]+-[0-9]+ from TOPdesk@UZH:`
      where `I-[0-9]+-[0-9]+` is the incident number in TOPDesk

    a mail should be sent to [email protected] to close the
    ticket. The reply email should have:

    * `From:` field equal to `[email protected]`
    * `To:` is equal to `[email protected]`
    * `Subject:` must contains the incident ID. Even better, we just
      leave the original subject and prepend Re:, as it was a reply
      from a regular user.

    Content of the email will include:

    Your ticket was transfered to RoundUp: http://....

    and possibly the content of the ticket.

    """

    log = db.get_logger()
    log.debug("TOPDesk-RoundUp integration - new issue %s created", nodeid)

    # Check if this issue comes from TOPDesk
    msgids = cl.get(nodeid, 'messages')

    # one and only one message should be here.
    if len(msgids) > 1:
        log.warning("Issue %s has more than one message, which is wrong. "
                    "Only parsing first message.",
                    nodeid)
    elif len(msgids) == 0:
        # We don't know what to do with an issue with more than one message.
        # Just skip it
        log.warning("Issue %s has no message. Unable to check if it comes "
                    "from TOPDesk. Skipping.")
	return

    msgid = msgids[0]
    msg = db.msg.getnode(msgid)
    content = msg.content
    firstline = content.strip().split('\n')[0]

    if re_forwarded.match(firstline):
        # Send a reply to [email protected]

        # Get the URL of the roundup issue
        base = db.config.TRACKER_WEB
        if not base.endswith('/'):
            base = base + '/'
        issue_url = base + cl.classname + nodeid

        # Get the requestor name
        userid = cl.get(nodeid, 'creator')
        username = db.user.get(userid, 'realname')

        # Get the ID of the issue on TOPDesk
        topdesk_id = re_forwarded.search(firstline).group(1)

        # Mail from is fixed
        mail_from = '*****@*****.**'

        # Mail to is fixed
        mail_to = '*****@*****.**'

        # Subject is took from the original subject, that is now the
        # title of the issue
        mail_subject = 'Re: ' + cl.get(nodeid, 'title')

        # Build the reply message.
        # Please note that this message will be sent from TOPDesk to the user
        message = msg.content
        
        mail_body = replymessage_template % {
            'mail_from': mail_from,
            'mail_subject': mail_subject,
            'username': username,
            'issue_url': issue_url,
            'message': message,
            'topdeskid': topdesk_id,
        }

        try:
            mailer = Mailer(db.config)
            mailer.smtp_send([mail_to], mail_body, sender=mail_from)
            log.info("Sent reply to %s for issue %s (%s)." % (
                mail_to, nodeid, topdesk_id))
            db.addjournal(db.issue.classname, nodeid, 'topdesk-notified', {})
        except Exception as ex:
            raise roundupdb.DetectorError(
                "Error sending reply message for TOPDesk issue %s "
                "(RoundUp issue %s): %s",
                topdesk_id, nodeid, ex)