Ejemplo n.º 1
0
 def __mail(self, mailingID):  #{{{
     try:
         rc = self.mailingInfo[mailingID]
     except KeyError:
         r = self.cursor.querys(
             'SELECT company_id, shortname, deleted FROM mailing_tbl WHERE mailing_id = :mid',
             {'mid': mailingID})
         if r is not None:
             rc = agn.mutable(companyID=r[0],
                              name=self.__toiso(r[1]),
                              deleted=bool(r[2]))
         else:
             rc = agn.mutable(companyID=0,
                              name='#%d not found' % mailingID,
                              deleted=False)
         self.mailingInfo[mailingID] = rc
     return rc
Ejemplo n.º 2
0
	def controllerSetup (self):
		defaults = [
			('xmlrpc.host', 'localhost'),
			('xmlrpc.port', 9400),
			('xmlrpc.allow_none', True)
		]
		for (var, value) in defaults:
			if var not in self.cfg:
				self.cfg[var] = value
		ctx = agn.mutable (last = 0)
		return ctx
Ejemplo n.º 3
0
 def __answer(self, ok, s):
     if ok:
         agn.log(agn.LV_DEBUG, 'answer', 'OK : %s' % s)
         content = '+OK: %s\n' % s
     else:
         agn.log(agn.LV_INFO, 'answer', 'ERR: %s' % s)
         content = '-ERR: %s\n' % s
     return agn.mutable(code=200,
                        mime='text/plain',
                        headers=None,
                        content=content)
Ejemplo n.º 4
0
			def find (key, defaultValue):
				rc = agn.mutable (path = None, content = [], modified = False, hash = None)
				try:
					for element in self.mta.getlist (key):
						try:
							(hash, path) = element.split (':', 1)
						except ValueError:
							hash = None
							path = element
						if path.startswith (agn.base):
							if rc.path is None:
								rc.path = path
								rc.hash = hash
							if not os.path.isfile (path):
								agn.createPath (os.path.dirname (path))
								open (path, 'w').close ()
								if hash is not None:
									self.mta.postfixMake (path)
					if rc.path is not None:
						try:
							fd = open (rc.path)
							for line in (_l.strip () for _l in fd):
								try:
									(var, val) = [_v.strip () for _v in line.split (None, 1)]
								except ValueError:
									var = line
									val = defaultValue
									rc.modified = True
								if var not in [_c[0] for _c in rc.content]:
									rc.content.append ((var, val))
								else:
									rc.modified = True
							fd.close ()
							agn.log (agn.LV_VERBOSE, 'data', 'Read %d lines from %s' % (len (rc.content), rc.path))
						except OSError, e:
							agn.log (agn.LV_ERROR, 'data', 'Failed to read %s: %s' % (rc.path, str (e)))
Ejemplo n.º 5
0
	def enrich (self):
		rc = self.msg
		if not self.rule.enrich is None:
			mailinfo = agn.mutable (type = 'text/plain', charset = 'ISO-8859-1')
			inlined = False
			try:
				filled = self.rule.enrich.fill (self.makeNamespace (mailinfo, self.rule.enrich.property ('limit-clause')))
				inlined = self.rule.enrich.property ('inline')
			except agn.error as e:
				filled = None
				agn.log (agn.LV_ERROR, 'enrich', 'Failed to fill template for rule %s: %s' % (self.rule.rid, e))
			if not filled is None and len (filled.strip ()) > 0:
				rc = email.Message.Message ()
				for (var, val) in self.msg.items ():
					rc[var] = val
				if inlined:
					if self.msg.is_multipart ():
						text = self.msg.as_string (False).replace ('\r\n', '\n')
						n = text.find ('\n\n')
						if n != -1:
							text = text[n + 2:]
					else:
						text = self.msg.get_payload (decode = True)
					if text is None:
						text = filled
					else:
						text = filled + '\n' + text
					rc.set_payload (text, mailinfo.charset)
				else:
					rc.set_type ('multipart/mixed')
					info = email.Message.Message ()
					info.set_type (mailinfo.type)
					info.set_payload (filled, mailinfo.charset)
					rc.attach (info)
					rc.attach (self.msg)
		return rc
Ejemplo n.º 6
0
 def reportMailings(self):  #{{{
     mails = []
     query = 'SELECT status_id, mailing_id, genstatus, genchange, status_field, senddate FROM maildrop_status_tbl WHERE '
     query += 'genstatus IN (1, 2) AND status_field IN (\'W\', \'R\', \'D\')'
     for (statusID, mailingID, genStatus, genChange, statusField,
          sendDate) in self.cursor.queryc(query):
         if statusField in ('R', 'D') and genStatus == 1:
             continue
         info = self.__mail(mailingID)
         mail = agn.mutable(statusID=statusID,
                            statusField=statusField,
                            mailingID=mailingID,
                            mailingName=info.name,
                            companyID=info.companyID,
                            deleted=info.deleted,
                            genChange=genChange,
                            sendDate=sendDate)
         mails.append(mail)
     if self.report or mails:
         template = agn.mkpath(agn.base, 'scripts', 'recovery.tmpl')
         try:
             fd = open(template, 'r')
             content = fd.read()
             fd.close()
         except IOError, e:
             agn.log(
                 agn.LV_ERROR, 'report',
                 'Unable to find template "%s": %r' % (template, e.args))
             content = None
         if content:
             ns = {
                 'host': socket.getfqdn(),
                 'report': self.report,
                 'mails': mails
             }
             tmpl = agn.Template(content)
             try:
                 body = tmpl.fill(ns)
             except agn.error as e:
                 agn.log(agn.LV_ERROR, 'report',
                         'Failed to fill template "%s": %s' % (template, e))
                 body = None
             if body:
                 charset = tmpl.property('charset')
                 subject = tmpl.property('subject')
                 if not subject:
                     subject = tmpl['subject']
                 if not subject:
                     subject = 'Recovery report for %s' % ns['host']
                 else:
                     stmpl = agn.Template(subject)
                     subject = stmpl.fill(ns)
                 sender = tmpl.property('sender')
                 if not sender:
                     sender = 'openemm'
                 receiver = tmpl.property('receiver')
                 if not receiver:
                     receiver = 'openemm'
                 if self.doit:
                     if charset:
                         eagn.EMail.forceEncoding(charset, 'qp')
                     mail = eagn.EMail()
                     mail.setSender(sender)
                     for recv in [_r.strip() for _r in receiver.split(',')]:
                         if recv:
                             mail.addTo(recv)
                     if charset:
                         mail.setCharset(charset)
                     mail.setSubject(subject)
                     mail.setText(body)
                     mail.sendMail()
                 else:
                     print('From: %s' % sender)
                     print('To: %s' % receiver)
                     print('Subject: %s' % subject)
                     print('')
                     print(body)
Ejemplo n.º 7
0
	def readDatabase (self, auto):
		rc = []
		db = agn.DBaseID ()
		if not db:
			agn.log (agn.LV_ERROR, 'data', 'Unable to create database connection')
			raise agn.error ('readDatabase.open')
		try:
			i = db.cursor ()
			if not i:
				agn.log (agn.LV_ERROR, 'data', 'Unable to get database cursor')
				raise agn.error ('readDatabase.cursor')
			try:
				fqdn = socket.getfqdn ().lower ()
				company_list = []
				newDomains = {}
				forwards = []
				seen = set ()
				acceptedForwards = set ()
				ctab = {}
				if self.domains:
					domain = self.domains[0]
				else:
					domain = self.fixdomain
				seen.add (domain)
				rc.append ('fbl@%s\taccept:rid=unsubscribe' % domain)
				query = 'SELECT company_id, mailloop_domain FROM company_tbl WHERE status = \'active\''
				missing = []
				for record in i.query (query):
					if record[1]:
						ctab[record[0]] = record[1]
						if record[1] not in seen:
							rc.append ('fbl@%s\talias:fbl@%s' % (record[1], domain))
							if record[1] not in self.mtdom and record[1].lower () != fqdn:
								newDomains[record[1]] = agn.mutable (rid = 0, domain = record[1])
							seen.add (record[1])
					else:
						missing.append (record[0])
					company_list.append (record[0])
				if missing:
					missing.sort ()
					agn.log (agn.LV_VERBOSE, 'data', 'Missing mailloop_domain for %s' % ', '.join ([str (m) for m in missing]))
				seen.clear ()
				#
				query = 'SELECT rid, shortname, company_id, filter_address, forward_enable, forward, ar_enable, ar_sender, ar_subject, ar_text, ar_html, subscribe_enable, mailinglist_id, form_id, timestamp, spam_email, spam_required, spam_forward, autoresponder_mailing_id, security_token FROM mailloop_tbl'
				apattern = re.compile ('alias(es)?="([^"]+)"')
				dpattern = re.compile ('domains?="([^"]+)"')
				for record in i.query (query):
					subscribe_enable = None
					mailinglist_id = None
					form_id = None
					(rid, shortname, company_id, filteraddr, forward_enable, forward, ar_enable, ar_sender, ar_subject, ar_text, ar_html, subscribe_enable, mailinglist_id, form_id, timestamp, spam_email, spam_required, spam_forward, autoresponder_mailing_id, security_token) = record
					if not company_id in company_list:
						continue
					if not rid is None:
						seen.add (rid)
						rid = str (rid)
						domains = None
						if timestamp is None:
							now = time.localtime ()
							timestamp = now[5] + now[4] * 100 + now[3] * 10000 + now[2] * 1000000 + now[1] * 100000000 + now[0] *  10000000000
						else:
							timestamp = timestamp.second + timestamp.minute * 100 + timestamp.hour * 10000 + timestamp.day * 1000000 + timestamp.month * 100000000 + timestamp.year * 10000000000
						aliases = None
						if not filteraddr is None:
							aliases = filteraddr.split ()
							if not aliases:
								aliases = None
						collect_domains = False
						if not shortname is None:
							mtch = apattern.search (shortname)
							if not mtch is None:
								tempaliases = (mtch.groups ()[1]).split ()
								if aliases is None:
									aliases = tempaliases
								else:
									aliases += tempaliases
							mtch = dpattern.search (shortname)
							if not mtch is None:
								domains = (mtch.groups ()[0]).split ()
								for domain in domains:
									if not self.mtdom.has_key (domain) and not domain in newDomains:
										newDomains[domain] = agn.mutable (rid = rid, domain = domain)
							else:
								collect_domains = True	
						if not aliases is None:
							for alias in aliases:
								if not alias.startswith (self.prefix):
									parts = alias.split ('@')
									if len (parts) == 2:
										if collect_domains:
											if domains is None:
												domains = [parts[1]]
											else:
												domains.append (parts[1])
										if not self.mtdom.has_key (parts[1]) and not parts[1] in newDomains:
											newDomains[parts[1]] = agn.mutable (rid = rid, domain = parts[1])
						if autoresponder_mailing_id:
							try:
								autoresponder_mailing_id = int (autoresponder_mailing_id)
								if not security_token:
									agn.log (agn.LV_ERROR, 'data', '%s: Autoresponder has mailing id, but no security token' % rid)
									autoresponder_mailing_id = None
							except ValueError, e:
								agn.log (agn.LV_ERROR, 'data', '%s: Failed to parse autoresponder_mailing_id %r: %s' % (rid, autoresponder_mailing_id, str (e)))
								autoresponder_mailing_id = None

						if ar_enable and not ar_text and not autoresponder_mailing_id:
							ar_enable = False
						if ar_enable:
							def nvl (s):
								if s is not None and type (s) not in (str, unicode):
									return str (s)
								return s
							auto.append (Autoresponder (rid, timestamp, ar_sender, ar_subject, nvl (ar_text), nvl (ar_html), autoresponder_mailing_id, security_token))
						if domains is None:
							try:
								cdomain = ctab[company_id]
								if self.domains and cdomain != self.domains[0]:
									domains = [self.domains[0]]
								else:
									domains = []
								if not self.domains or cdomain in self.domains:
									domains.append (cdomain)

								else:
									agn.log (agn.LV_ERROR, 'data', 'Companys domain "%s" not found in mailertable' % cdomain)
							except KeyError:
								agn.log (agn.LV_DEBUG, 'data', 'No domain for company found, further processing')
						if domains is None:
							domains = self.domains
						elif self.domains and self.domains[0] not in domains:
							domains.insert (0, self.domains[0])
						extra = 'rid=%s' % rid
						if company_id:
							extra += ',cid=%d' % company_id
						if forward_enable and forward:
							extra += ',fwd=%s' % forward
							forwards.append (agn.mutable (rid = rid, address = forward))
                                                if spam_email:
                                                        extra += ',spam_email=%s' % spam_email
                                                if spam_forward is not None:
                                                        extra += ',spam_fwd=%d' % spam_forward
                                                if spam_required is not None:
                                                        extra += ',spam_req=%d' % spam_required
						if ar_enable:
							extra += ',ar=%s' % rid
							if autoresponder_mailing_id:
								extra += ',armid=%d' % autoresponder_mailing_id
						if subscribe_enable and mailinglist_id and form_id:
							extra += ',sub=%d:%d' % (mailinglist_id, form_id)

						for domain in domains:
							line = '%s%s@%s\taccept:%s' % (self.prefix, rid, domain, extra)
							agn.log (agn.LV_VERBOSE, 'data', 'Add line: ' + line)
							rc.append (line)
						if aliases and domains:
							for alias in aliases:
								rc.append ('%s\talias:%s%s@%s' % (alias, self.prefix, rid, domains[0]))
								acceptedForwards.add (alias)
				if seen:
					rules = {}
					query = 'SELECT rid, section, pattern FROM mailloop_rule_tbl'
					for (rid, section, pattern) in i.query (query):
						if rid in seen:
							try:
								rule = rules[rid]
							except KeyError:
								rule = {}
								rules[rid] = rule
							try:
								sect = rule[section]
							except KeyError:
								sect = []
								rule[section] = sect
							sect.append (pattern)
					self.updateRules (rules)

				for forward in forwards:
					parts = forward.address.split ('@')
					if len (parts) == 2:
						fdomain = parts[1].lower ()
						for domain in self.mtdom:
							if domain == fdomain and forward not in acceptedForwards:
								agn.log (agn.LV_WARNING, 'db', '%s: using address "%s" with local handled domain "%s"' % (forward.rid, forward.address, domain))
						refuse = []
						for domain in newDomains:
							if domain == fdomain:
								nd = newDomains[domain]
								agn.log (agn.LV_WARNING, 'db', '%s: try to add new domain for already existing forward address "%s" in %s, refused' % (nd.rid, forward.address, forward.rid))
								refuse.append (domain)
						for domain in refuse:
							del newDomains[domain]

				if newDomains:
					if agn.sDNS is not None:
						try:
							dns = agn.sDNS ()
							laddrs = dns.getAllAddresses (fqdn)
							for domain in newDomains:
								checks = dns.getMailexchanger (domain)
								if not checks:
									checks = [domain]
								if checks:
									for check in checks:
										caddrs = dns.getAllAddresses (check)
										for caddr in caddrs:
											if caddr not in laddrs:
												agn.log (agn.LV_ERROR, 'db', '%s: checked address "%s" for "%s" does not point to local machines address %s' % (domain, caddr, check, ', '.join (laddrs)))
								else:
									agn.log (agn.LV_ERROR, 'db', '%s: failed to resolve' % domain)
						except Exception, e:
							agn.log (agn.LV_ERROR, 'db', 'Failed to verify new domains: %s' % str (e))
					if self.mta.mta == 'sendmail':
						chandler = signal.signal (signal.SIGUSR1, signal.SIG_IGN)
						cmd = [self.controlSendmail, 'add']
						for domain in newDomains:
							cmd.append (domain)
						agn.log (agn.LV_INFO, 'db', 'Found new domains, add them using ' + `cmd`)
						subprocess.call (cmd)
						agn.log (agn.LV_INFO, 'db', 'Restarting sendmail due to domain update')
						subprocess.call ([self.restartSendmail])
						signal.signal (signal.SIGUSR1, chandler)
					self.readMailertable (newDomains)
			finally:
				i.close ()
Ejemplo n.º 8
0
	def executorSetup (self):
		ctx = agn.mutable (
			process = Processor ()
		)
		return ctx
Ejemplo n.º 9
0
	def makeNamespace (self, mailinfo, limitClause):
		ns = {'agn': agn, 'mailinfo': mailinfo, 'user': None, 'mail': None}
		cinfo = self.cinfo
		if cinfo is None:
			cinfo = agn.mutable (customerID = None, mailingID = None)
		if cinfo.customerID is None or cinfo.mailingID is None:
			sm = self.rule.scanMessage (cinfo, self.msg, None)
			if not sm.minfo is None:
				if cinfo.customerID is None:
					cinfo.customerID = sm.minfo.customerID
				if cinfo.mailingID is None:
					cinfo.mailingID = sm.minfo.mailingID
		if self.companyID > 0:
			db = agn.DBaseID ()
			if not db is None:
				cursor = db.cursor ()
				if not cursor is None:
					if cinfo.customerID is None:
						for state in [0, 1]:
							if state == 0:
								if not limitClause:
									continue
								addClause = ' AND %s' % limitClause
							else:
								addClause = ''
							for eMail in [self.sender, self.headerFrom and self.headerFrom[1].lower () or None]:
								if not eMail:
									continue
								for r in cursor.query ('SELECT customer_id FROM customer_%d_tbl WHERE email = :email%s' % (self.companyID, addClause), {'email': eMail}):
									if not r[0] is None:
										if cinfo.customerID is None or r[0] > cinfo.customerID:
											cinfo.customerID = r[0]
								if not cinfo.customerID is None:
									break
							if not cinfo.customerID is None:
								break
					if not cinfo.customerID is None:
						user = agn.mutable ()
						for r in cursor.query ('SELECT * FROM customer_%d_tbl WHERE customer_id = :cid' % self.companyID, {'cid': cinfo.customerID}):
							desc = cursor.description ()
							if not desc is None:
								n = 0
								while n < len (desc):
									user.__dict__[desc[n][0].lower ()] = r[n]
									n += 1
								break
						user.binding = {}
						for r in cursor.query ('SELECT mailinglist_id, user_type, user_status, user_remark, timestamp, creation_date, exit_mailing_id, mediatype FROM customer_%d_binding_tbl WHERE customer_id = :cid' % self.companyID, {'cid': cinfo.customerID}):
							bind = agn.mutable (
								list_id = r[0],
								type = r[1],
								status = r[2],
								remark = r[3],
								timestamp = r[4],
								creation_date = r[5],
								exit_id = r[6],
								media = r[7]
							)
							user.binding[r[0]] = bind
						ns['user'] = user
					if not cinfo.mailingID is None:
						mail = agn.mutable ()
						for r in cursor.query ('SELECT shortname, description, creation_date, mailinglist_id FROM mailing_tbl WHERE mailing_id = :mid', {'mid': cinfo.mailingID}):
							mail.shortname = r[0]
							mail.description = r[1]
							mail.creation_date = r[2]
							mail.list_id = r[3]
						mail.status_field = None
						for r in cursor.query ('SELECT status_field, senddate FROM maildrop_status_tbl WHERE mailing_id = :mid', {'mid': cinfo.mailingID}):
							if not r[0] is None:
								if r[0] in ('W', 'D', 'R', 'E'):
									mail.status_field = r[0]
									if r[0] == 'W':
										mail.senddate = r[1]
									elif r[0] == 'R':
										mail.sendhour = r[1].hour
								elif mail.status_field is None or (mail.status_field == 'A' and r[0] == 'T'):
									mail.status_field = r[0]
						ns['mail'] = mail
					cursor.close ()
				db.close ()
		ns['rid'] = self.rid
		ns['company_id'] = self.companyID
		ns['sender'] = self.sender
		ns['customer_id'] = cinfo.customerID
		ns['mailing_id'] = cinfo.mailingID
		return ns
Ejemplo n.º 10
0
    def convertToHardbounce(self):  #{{{
        agn.log(agn.LV_INFO, 'conv',
                'Start converting softbounces to hardbounce')
        coll = self.__ccoll(
            'SELECT distinct company_id FROM softbounce_email_tbl WHERE company_id IN (SELECT company_id FROM company_tbl WHERE status = \'active\')',
            None, None, None)
        stats = []
        for company in sorted(coll):
            cstat = [company, 0, 0]
            stats.append(cstat)
            agn.log(agn.LV_INFO, 'conv', 'Working on %d' % company)
            dquery = 'DELETE FROM softbounce_email_tbl WHERE company_id = %d AND email = :email' % company
            dcurs = self.db.cursor()
            uquery = self.curs.rselect(
                'UPDATE customer_%d_binding_tbl SET user_status = 2, user_remark = \'bounce:soft\', exit_mailing_id = :mailing, timestamp = %%(sysdate)s WHERE customer_id = :customer AND user_status = 1'
                % company)
            bquery = self.curs.rselect(
                'INSERT INTO bounce_tbl (company_id, customer_id, detail, mailing_id, timestamp, dsn) VALUES (%d, :customer, 510, :mailing, %%(sysdate)s, 599)'
                % company)
            ucurs = self.db.cursor()
            squery = 'SELECT email, mailing_id, bnccnt, creation_date, timestamp FROM softbounce_email_tbl '
            bnccnt = self.__cfg(company, 'convert-bounce-count', 40)
            daydiff = self.__cfg(company, 'convert-bounce-duration', 30)
            squery += self.curs.qselect(
                oracle=
                'WHERE company_id = %d AND bnccnt > %d AND timestamp-creation_date > %d'
                % (company, bnccnt, daydiff),
                mysql=
                'WHERE company_id = %d AND bnccnt > %d AND DATEDIFF(timestamp,creation_date) > %d'
                % (company, bnccnt, daydiff))
            scurs = self.db.cursor()
            if None in [dcurs, ucurs, scurs]:
                raise agn.error('Failed to setup curses')
            lastClick = self.__cfg(company, 'last-click', 30)
            lastOpen = self.__cfg(company, 'last-open', 30)

            def toDatetime(offset):
                tm = time.localtime(time.time() - offset * 24 * 60 * 60)
                return datetime.datetime(tm.tm_year, tm.tm_mon, tm.tm_mday)

            lastClickTS = toDatetime(lastClick)
            lastOpenTS = toDatetime(lastOpen)
            if Cache is not None:
                rcache = Cache(1000)
                ocache = Cache(1000 * 1000)
                ccurs = self.db.cursor()
                if None in [rcache, ocache, ccurs
                            ] or not rcache.valid() or not ocache.valid():
                    raise agn.error('Failed to setup caching')
                agn.log(agn.LV_INFO, 'cache',
                        'Setup rdir log cache for %d' % company)
                query = 'SELECT customer_id FROM rdirlog_%d_tbl WHERE timestamp > :ts' % company
                parm = {'ts': lastClickTS}
                for record in ccurs.query(query, parm):
                    rcache.add(record[0])
                agn.log(agn.LV_INFO, 'cache',
                        'Setup one pixel log cache for %d' % company)
                query = 'SELECT customer_id FROM onepixellog_%d_tbl WHERE timestamp > :ts' % company
                parm = {'ts': lastOpenTS}
                for record in ccurs.query(query, parm):
                    ocache.add(record[0])
                ccurs.close()
                agn.log(agn.LV_INFO, 'cache', 'Setup completed')
            ccount = 0
            for record in scurs.query(squery):
                parm = {
                    'email': record[0],
                    'mailing': record[1],
                    'bouncecount': record[2],
                    'creationdate': record[3],
                    'timestamp': record[4],
                    'customer': None
                }
                query = 'SELECT customer_id FROM customer_%d_tbl WHERE email = :email ' % company
                data = self.curs.querys(query, parm, cleanup=True)
                if data is None:
                    continue
                custs = [
                    agn.mutable(id=_d, click=0, open=0) for _d in data if _d
                ]
                if not custs:
                    continue
                if len(custs) == 1:
                    cclause = 'customer_id = %d' % custs[0].id
                else:
                    cclause = 'customer_id IN (%s)' % ', '.join(
                        [str(_c.id) for _c in custs])
                if Cache is not None:
                    for c in custs:
                        c.click += rcache.get(c.id, 0)
                        c.open += ocache.get(c.id, 0)
                else:
                    parm['ts'] = lastClickTS
                    query = 'SELECT customer_id, count(*) FROM rdirlog_%d_tbl WHERE %s AND timestamp > :ts GROUP BY customer_id' % (
                        company, cclause)
                    for r in self.curs.queryc(query, parm, cleanup=True):
                        for c in custs:
                            if c.id == r[0]:
                                c.click += r[1]
                    parm['ts'] = lastOpenTS
                    query = 'SELECT customer_id, count(*) FROM onepixellog_%d_tbl WHERE %s AND timestamp > :ts GROUP BY customer_id' % (
                        company, cclause)
                    for r in self.curs.queryc(query, parm, cleanup=True):
                        for c in custs:
                            if c.id == r[0]:
                                c.open += r[1]
                for c in custs:
                    if c.click > 0 or c.open > 0:
                        cstat[1] += 1
                        agn.log(
                            agn.LV_INFO, 'conv',
                            'Email %s [%d] has %d klick(s) and %d onepix(es) -> active'
                            % (parm['email'], c.id, c.click, c.open))
                    else:
                        cstat[2] += 1
                        agn.log(
                            agn.LV_INFO, 'conv',
                            'Email %s [%d] has no klicks and no onepixes -> hardbounce'
                            % (parm['email'], c.id))
                        parm['customer'] = c.id
                        ucurs.update(uquery, parm, cleanup=True)
                        ucurs.execute(bquery, parm, cleanup=True)
                dcurs.update(dquery, parm, cleanup=True)
                ccount += 1
                if ccount % 1000 == 0:
                    agn.log(agn.LV_INFO, 'conv',
                            'Commiting at %s' % agn.numfmt(ccount))
                    self.db.commit()
            if Cache is not None:
                rcache.done()
                ocache.done()
            self.db.commit()
            scurs.close()
            ucurs.close()
            dcurs.close()
        for cstat in stats:
            agn.log(
                agn.LV_INFO, 'conv',
                'Company %d has %d active and %d marked as hardbounced users' %
                tuple(cstat))
        agn.log(agn.LV_INFO, 'conv',
                'Converting softbounces to hardbounce done')
Ejemplo n.º 11
0
    def execute(self, param):
        if len(param) == 0:
            command = Process.knownCommands[0]
            selective = None
        else:
            command = param[0]
            if command not in Process.knownCommands:
                self.fail('Command %s unknown, available commands are %s' %
                          (command, ', '.join(Process.knownCommands)))
                return
            selective = set(param[1:])
        found = set()
        #
        procs = []
        depends = agn.mutable(require=set(), resolved=set())
        for name in [
                _n for _n in self.cfg.getSectionSequence()
                if not _n.startswith('_')
        ]:
            if not selective or name in selective or name in depends.require:
                self.cfg.push(name)
                self.cfg.ns['service'] = name
                if self.active(name):
                    try:
                        proc = Process(
                            self.cfg, name,
                            lambda method, args, default: self.call(
                                name, method, args, default))
                        proc.doStatus()
                        procs.append(proc)
                        depend = self.cfg.lget('depends-on')
                        if depend:
                            depends.require.update(depend)
                        if name in depends.require:
                            depends.resolved.add(name)
                    except error as e:
                        self.fail('%s: unable to setup: %s' % (proc.name, e))
                        self.info(e.token, e.ns)
                self.cfg.pop()
                found.add(name)
        if selective:
            diff = selective.difference(found)
            if diff:
                self.fail('unknown modules %s selected' %
                          ', '.join(list(diff)))
        if depends.require != depends.resolved:
            self.fail(
                'Failed to resolve required modules %s' %
                ', '.join(list(depends.require.difference(depends.resolved))))
        if self.ec != 0:
            return
        #
        if command in ('start', 'stop', 'restart'):
            ta = eagn.Transaction()
            if command == 'stop':
                use = list(reversed(procs))
            else:
                use = procs
            for proc in use:
                if command == 'start':
                    execute = proc.doStart if proc.can('start') else None
                    rollback = proc.doStop if proc.can('stop') else None
                elif command == 'stop':
                    execute = proc.doStop if proc.can('stop') else None
                    rollback = proc.doStart if proc.can('start') else None
                elif command == 'restart':
                    execute = proc.doRestart if proc.can('start') else None
                    rollback = proc.doRestore
                else:
                    agn.log(agn.LV_ERROR, 'execute',
                            'Unknown command %s for %s' % (command, proc.name))
                    continue
                #
                ta.add(proc.name, method=execute, rollback=rollback)

            def callback(name, what, e=None):
                if what in ('start', 'rollback'):
                    if what == 'start':
                        what = command
                    self.outn('%s %s .. ' % (what, name))
                else:
                    self.out('%s%s' % (what, (' (%s)' % str(e)) if e else ''))
                    if what == 'fail':
                        time.sleep(2)
                        for proc in use:
                            try:
                                proc.doStatus()
                            except error as e:
                                agn.log(
                                    agn.LV_ERROR, 'rollback',
                                    'Failed to get status for %s before rollback'
                                    % proc.name)

            def handler(sig, stack):
                pass

            handlers = []
            for (sig, hand) in [(signal.SIGINT, handler)]:
                ohand = signal.signal(sig, hand)
                handlers.append((sig, ohand))
            try:
                ta.execute(rollbackFailed=True, callback=callback)
            except Exception as e:
                self.fail('Rollback executed during %s: %s' %
                          (command, str(e)))
                if isinstance(e, error):
                    self.info(e.token, e.ns)
            for (sig, hand) in handlers:
                signal.signal(sig, hand)
            time.sleep(2)
            for proc in use:
                try:
                    proc.doStatus()
                except error as e:
                    self.fail('%s: unable to query status: %s' %
                              (proc.name, e))
                    self.info(e.token, e.ns)
        #
        if procs:
            nlen = max([len(_p.name) for _p in procs]) + 1
            format = '%%-%d.%ds: %%s' % (nlen, nlen)
            for proc in procs:
                if proc.status:
                    if proc.comment:
                        status = '%s (%s)' % (proc.status, proc.comment)
                    else:
                        status = proc.status
                    self.out(format % (proc.name, status))
        else:
            self.out('No active processes')