aboutsummaryrefslogtreecommitdiffstats
path: root/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/news/database.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/news/database.py')
-rwxr-xr-xlib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/news/database.py1051
1 files changed, 0 insertions, 1051 deletions
diff --git a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/news/database.py b/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/news/database.py
deleted file mode 100755
index 137736a2..00000000
--- a/lib/python2.7/site-packages/Twisted-12.2.0-py2.7-linux-x86_64.egg/twisted/news/database.py
+++ /dev/null
@@ -1,1051 +0,0 @@
-# -*- test-case-name: twisted.news.test -*-
-# Copyright (c) Twisted Matrix Laboratories.
-# See LICENSE for details.
-
-"""
-News server backend implementations.
-"""
-
-import getpass, pickle, time, socket
-import os
-import StringIO
-from email.Message import Message
-from email.Generator import Generator
-from zope.interface import implements, Interface
-
-from twisted.news.nntp import NNTPError
-from twisted.mail import smtp
-from twisted.internet import defer
-from twisted.enterprise import adbapi
-from twisted.persisted import dirdbm
-from twisted.python.hashlib import md5
-
-
-
-ERR_NOGROUP, ERR_NOARTICLE = range(2, 4) # XXX - put NNTP values here (I guess?)
-
-OVERVIEW_FMT = [
- 'Subject', 'From', 'Date', 'Message-ID', 'References',
- 'Bytes', 'Lines', 'Xref'
-]
-
-def hexdigest(md5): #XXX: argh. 1.5.2 doesn't have this.
- return ''.join(map(lambda x: hex(ord(x))[2:], md5.digest()))
-
-class Article:
- def __init__(self, head, body):
- self.body = body
- self.headers = {}
- header = None
- for line in head.split('\r\n'):
- if line[0] in ' \t':
- i = list(self.headers[header])
- i[1] += '\r\n' + line
- else:
- i = line.split(': ', 1)
- header = i[0].lower()
- self.headers[header] = tuple(i)
-
- if not self.getHeader('Message-ID'):
- s = str(time.time()) + self.body
- id = hexdigest(md5(s)) + '@' + socket.gethostname()
- self.putHeader('Message-ID', '<%s>' % id)
-
- if not self.getHeader('Bytes'):
- self.putHeader('Bytes', str(len(self.body)))
-
- if not self.getHeader('Lines'):
- self.putHeader('Lines', str(self.body.count('\n')))
-
- if not self.getHeader('Date'):
- self.putHeader('Date', time.ctime(time.time()))
-
-
- def getHeader(self, header):
- h = header.lower()
- if h in self.headers:
- return self.headers[h][1]
- else:
- return ''
-
-
- def putHeader(self, header, value):
- self.headers[header.lower()] = (header, value)
-
-
- def textHeaders(self):
- headers = []
- for i in self.headers.values():
- headers.append('%s: %s' % i)
- return '\r\n'.join(headers) + '\r\n'
-
- def overview(self):
- xover = []
- for i in OVERVIEW_FMT:
- xover.append(self.getHeader(i))
- return xover
-
-
-class NewsServerError(Exception):
- pass
-
-
-class INewsStorage(Interface):
- """
- An interface for storing and requesting news articles
- """
-
- def listRequest():
- """
- Returns a deferred whose callback will be passed a list of 4-tuples
- containing (name, max index, min index, flags) for each news group
- """
-
-
- def subscriptionRequest():
- """
- Returns a deferred whose callback will be passed the list of
- recommended subscription groups for new server users
- """
-
-
- def postRequest(message):
- """
- Returns a deferred whose callback will be invoked if 'message'
- is successfully posted to one or more specified groups and
- whose errback will be invoked otherwise.
- """
-
-
- def overviewRequest():
- """
- Returns a deferred whose callback will be passed the a list of
- headers describing this server's overview format.
- """
-
-
- def xoverRequest(group, low, high):
- """
- Returns a deferred whose callback will be passed a list of xover
- headers for the given group over the given range. If low is None,
- the range starts at the first article. If high is None, the range
- ends at the last article.
- """
-
-
- def xhdrRequest(group, low, high, header):
- """
- Returns a deferred whose callback will be passed a list of XHDR data
- for the given group over the given range. If low is None,
- the range starts at the first article. If high is None, the range
- ends at the last article.
- """
-
-
- def listGroupRequest(group):
- """
- Returns a deferred whose callback will be passed a two-tuple of
- (group name, [article indices])
- """
-
-
- def groupRequest(group):
- """
- Returns a deferred whose callback will be passed a five-tuple of
- (group name, article count, highest index, lowest index, group flags)
- """
-
-
- def articleExistsRequest(id):
- """
- Returns a deferred whose callback will be passed with a true value
- if a message with the specified Message-ID exists in the database
- and with a false value otherwise.
- """
-
-
- def articleRequest(group, index, id = None):
- """
- Returns a deferred whose callback will be passed a file-like object
- containing the full article text (headers and body) for the article
- of the specified index in the specified group, and whose errback
- will be invoked if the article or group does not exist. If id is
- not None, index is ignored and the article with the given Message-ID
- will be returned instead, along with its index in the specified
- group.
- """
-
-
- def headRequest(group, index):
- """
- Returns a deferred whose callback will be passed the header for
- the article of the specified index in the specified group, and
- whose errback will be invoked if the article or group does not
- exist.
- """
-
-
- def bodyRequest(group, index):
- """
- Returns a deferred whose callback will be passed the body for
- the article of the specified index in the specified group, and
- whose errback will be invoked if the article or group does not
- exist.
- """
-
-class NewsStorage:
- """
- Backwards compatibility class -- There is no reason to inherit from this,
- just implement INewsStorage instead.
- """
- def listRequest(self):
- raise NotImplementedError()
- def subscriptionRequest(self):
- raise NotImplementedError()
- def postRequest(self, message):
- raise NotImplementedError()
- def overviewRequest(self):
- return defer.succeed(OVERVIEW_FMT)
- def xoverRequest(self, group, low, high):
- raise NotImplementedError()
- def xhdrRequest(self, group, low, high, header):
- raise NotImplementedError()
- def listGroupRequest(self, group):
- raise NotImplementedError()
- def groupRequest(self, group):
- raise NotImplementedError()
- def articleExistsRequest(self, id):
- raise NotImplementedError()
- def articleRequest(self, group, index, id = None):
- raise NotImplementedError()
- def headRequest(self, group, index):
- raise NotImplementedError()
- def bodyRequest(self, group, index):
- raise NotImplementedError()
-
-
-
-class _ModerationMixin:
- """
- Storage implementations can inherit from this class to get the easy-to-use
- C{notifyModerators} method which will take care of sending messages which
- require moderation to a list of moderators.
- """
- sendmail = staticmethod(smtp.sendmail)
-
- def notifyModerators(self, moderators, article):
- """
- Send an article to a list of group moderators to be moderated.
-
- @param moderators: A C{list} of C{str} giving RFC 2821 addresses of
- group moderators to notify.
-
- @param article: The article requiring moderation.
- @type article: L{Article}
-
- @return: A L{Deferred} which fires with the result of sending the email.
- """
- # Moderated postings go through as long as they have an Approved
- # header, regardless of what the value is
- group = article.getHeader('Newsgroups')
- subject = article.getHeader('Subject')
-
- if self._sender is None:
- # This case should really go away. This isn't a good default.
- sender = 'twisted-news@' + socket.gethostname()
- else:
- sender = self._sender
-
- msg = Message()
- msg['Message-ID'] = smtp.messageid()
- msg['From'] = sender
- msg['To'] = ', '.join(moderators)
- msg['Subject'] = 'Moderate new %s message: %s' % (group, subject)
- msg['Content-Type'] = 'message/rfc822'
-
- payload = Message()
- for header, value in article.headers.values():
- payload.add_header(header, value)
- payload.set_payload(article.body)
-
- msg.attach(payload)
-
- out = StringIO.StringIO()
- gen = Generator(out, False)
- gen.flatten(msg)
- msg = out.getvalue()
-
- return self.sendmail(self._mailhost, sender, moderators, msg)
-
-
-
-class PickleStorage(_ModerationMixin):
- """
- A trivial NewsStorage implementation using pickles
-
- Contains numerous flaws and is generally unsuitable for any
- real applications. Consider yourself warned!
- """
-
- implements(INewsStorage)
-
- sharedDBs = {}
-
- def __init__(self, filename, groups=None, moderators=(),
- mailhost=None, sender=None):
- """
- @param mailhost: A C{str} giving the mail exchange host which will
- accept moderation emails from this server. Must accept emails
- destined for any address specified as a moderator.
-
- @param sender: A C{str} giving the address which will be used as the
- sender of any moderation email generated by this server.
- """
- self.datafile = filename
- self.load(filename, groups, moderators)
- self._mailhost = mailhost
- self._sender = sender
-
-
- def getModerators(self, groups):
- # first see if any groups are moderated. if so, nothing gets posted,
- # but the whole messages gets forwarded to the moderator address
- moderators = []
- for group in groups:
- moderators.extend(self.db['moderators'].get(group, None))
- return filter(None, moderators)
-
-
- def listRequest(self):
- "Returns a list of 4-tuples: (name, max index, min index, flags)"
- l = self.db['groups']
- r = []
- for i in l:
- if len(self.db[i].keys()):
- low = min(self.db[i].keys())
- high = max(self.db[i].keys()) + 1
- else:
- low = high = 0
- if self.db['moderators'].has_key(i):
- flags = 'm'
- else:
- flags = 'y'
- r.append((i, high, low, flags))
- return defer.succeed(r)
-
- def subscriptionRequest(self):
- return defer.succeed(['alt.test'])
-
- def postRequest(self, message):
- cleave = message.find('\r\n\r\n')
- headers, article = message[:cleave], message[cleave + 4:]
-
- a = Article(headers, article)
- groups = a.getHeader('Newsgroups').split()
- xref = []
-
- # Check moderated status
- moderators = self.getModerators(groups)
- if moderators and not a.getHeader('Approved'):
- return self.notifyModerators(moderators, a)
-
- for group in groups:
- if group in self.db:
- if len(self.db[group].keys()):
- index = max(self.db[group].keys()) + 1
- else:
- index = 1
- xref.append((group, str(index)))
- self.db[group][index] = a
-
- if len(xref) == 0:
- return defer.fail(None)
-
- a.putHeader('Xref', '%s %s' % (
- socket.gethostname().split()[0],
- ''.join(map(lambda x: ':'.join(x), xref))
- ))
-
- self.flush()
- return defer.succeed(None)
-
-
- def overviewRequest(self):
- return defer.succeed(OVERVIEW_FMT)
-
-
- def xoverRequest(self, group, low, high):
- if not self.db.has_key(group):
- return defer.succeed([])
- r = []
- for i in self.db[group].keys():
- if (low is None or i >= low) and (high is None or i <= high):
- r.append([str(i)] + self.db[group][i].overview())
- return defer.succeed(r)
-
-
- def xhdrRequest(self, group, low, high, header):
- if not self.db.has_key(group):
- return defer.succeed([])
- r = []
- for i in self.db[group].keys():
- if low is None or i >= low and high is None or i <= high:
- r.append((i, self.db[group][i].getHeader(header)))
- return defer.succeed(r)
-
-
- def listGroupRequest(self, group):
- if self.db.has_key(group):
- return defer.succeed((group, self.db[group].keys()))
- else:
- return defer.fail(None)
-
- def groupRequest(self, group):
- if self.db.has_key(group):
- if len(self.db[group].keys()):
- num = len(self.db[group].keys())
- low = min(self.db[group].keys())
- high = max(self.db[group].keys())
- else:
- num = low = high = 0
- flags = 'y'
- return defer.succeed((group, num, high, low, flags))
- else:
- return defer.fail(ERR_NOGROUP)
-
-
- def articleExistsRequest(self, id):
- for group in self.db['groups']:
- for a in self.db[group].values():
- if a.getHeader('Message-ID') == id:
- return defer.succeed(1)
- return defer.succeed(0)
-
-
- def articleRequest(self, group, index, id = None):
- if id is not None:
- raise NotImplementedError
-
- if self.db.has_key(group):
- if self.db[group].has_key(index):
- a = self.db[group][index]
- return defer.succeed((
- index,
- a.getHeader('Message-ID'),
- StringIO.StringIO(a.textHeaders() + '\r\n' + a.body)
- ))
- else:
- return defer.fail(ERR_NOARTICLE)
- else:
- return defer.fail(ERR_NOGROUP)
-
-
- def headRequest(self, group, index):
- if self.db.has_key(group):
- if self.db[group].has_key(index):
- a = self.db[group][index]
- return defer.succeed((index, a.getHeader('Message-ID'), a.textHeaders()))
- else:
- return defer.fail(ERR_NOARTICLE)
- else:
- return defer.fail(ERR_NOGROUP)
-
-
- def bodyRequest(self, group, index):
- if self.db.has_key(group):
- if self.db[group].has_key(index):
- a = self.db[group][index]
- return defer.succeed((index, a.getHeader('Message-ID'), StringIO.StringIO(a.body)))
- else:
- return defer.fail(ERR_NOARTICLE)
- else:
- return defer.fail(ERR_NOGROUP)
-
-
- def flush(self):
- f = open(self.datafile, 'w')
- pickle.dump(self.db, f)
- f.close()
-
-
- def load(self, filename, groups = None, moderators = ()):
- if filename in PickleStorage.sharedDBs:
- self.db = PickleStorage.sharedDBs[filename]
- else:
- try:
- self.db = pickle.load(open(filename))
- PickleStorage.sharedDBs[filename] = self.db
- except IOError:
- self.db = PickleStorage.sharedDBs[filename] = {}
- self.db['groups'] = groups
- if groups is not None:
- for i in groups:
- self.db[i] = {}
- self.db['moderators'] = dict(moderators)
- self.flush()
-
-
-class Group:
- name = None
- flags = ''
- minArticle = 1
- maxArticle = 0
- articles = None
-
- def __init__(self, name, flags = 'y'):
- self.name = name
- self.flags = flags
- self.articles = {}
-
-
-class NewsShelf(_ModerationMixin):
- """
- A NewStorage implementation using Twisted's dirdbm persistence module.
- """
-
- implements(INewsStorage)
-
- def __init__(self, mailhost, path, sender=None):
- """
- @param mailhost: A C{str} giving the mail exchange host which will
- accept moderation emails from this server. Must accept emails
- destined for any address specified as a moderator.
-
- @param sender: A C{str} giving the address which will be used as the
- sender of any moderation email generated by this server.
- """
- self.path = path
- self._mailhost = self.mailhost = mailhost
- self._sender = sender
-
- if not os.path.exists(path):
- os.mkdir(path)
-
- self.dbm = dirdbm.Shelf(os.path.join(path, "newsshelf"))
- if not len(self.dbm.keys()):
- self.initialize()
-
-
- def initialize(self):
- # A dictionary of group name/Group instance items
- self.dbm['groups'] = dirdbm.Shelf(os.path.join(self.path, 'groups'))
-
- # A dictionary of group name/email address
- self.dbm['moderators'] = dirdbm.Shelf(os.path.join(self.path, 'moderators'))
-
- # A list of group names
- self.dbm['subscriptions'] = []
-
- # A dictionary of MessageID strings/xref lists
- self.dbm['Message-IDs'] = dirdbm.Shelf(os.path.join(self.path, 'Message-IDs'))
-
-
- def addGroup(self, name, flags):
- self.dbm['groups'][name] = Group(name, flags)
-
-
- def addSubscription(self, name):
- self.dbm['subscriptions'] = self.dbm['subscriptions'] + [name]
-
-
- def addModerator(self, group, email):
- self.dbm['moderators'][group] = email
-
-
- def listRequest(self):
- result = []
- for g in self.dbm['groups'].values():
- result.append((g.name, g.maxArticle, g.minArticle, g.flags))
- return defer.succeed(result)
-
-
- def subscriptionRequest(self):
- return defer.succeed(self.dbm['subscriptions'])
-
-
- def getModerator(self, groups):
- # first see if any groups are moderated. if so, nothing gets posted,
- # but the whole messages gets forwarded to the moderator address
- for group in groups:
- try:
- return self.dbm['moderators'][group]
- except KeyError:
- pass
- return None
-
-
- def notifyModerator(self, moderator, article):
- """
- Notify a single moderator about an article requiring moderation.
-
- C{notifyModerators} should be preferred.
- """
- return self.notifyModerators([moderator], article)
-
-
- def postRequest(self, message):
- cleave = message.find('\r\n\r\n')
- headers, article = message[:cleave], message[cleave + 4:]
-
- article = Article(headers, article)
- groups = article.getHeader('Newsgroups').split()
- xref = []
-
- # Check for moderated status
- moderator = self.getModerator(groups)
- if moderator and not article.getHeader('Approved'):
- return self.notifyModerators([moderator], article)
-
-
- for group in groups:
- try:
- g = self.dbm['groups'][group]
- except KeyError:
- pass
- else:
- index = g.maxArticle + 1
- g.maxArticle += 1
- g.articles[index] = article
- xref.append((group, str(index)))
- self.dbm['groups'][group] = g
-
- if not xref:
- return defer.fail(NewsServerError("No groups carried: " + ' '.join(groups)))
-
- article.putHeader('Xref', '%s %s' % (socket.gethostname().split()[0], ' '.join(map(lambda x: ':'.join(x), xref))))
- self.dbm['Message-IDs'][article.getHeader('Message-ID')] = xref
- return defer.succeed(None)
-
-
- def overviewRequest(self):
- return defer.succeed(OVERVIEW_FMT)
-
-
- def xoverRequest(self, group, low, high):
- if not self.dbm['groups'].has_key(group):
- return defer.succeed([])
-
- if low is None:
- low = 0
- if high is None:
- high = self.dbm['groups'][group].maxArticle
- r = []
- for i in range(low, high + 1):
- if self.dbm['groups'][group].articles.has_key(i):
- r.append([str(i)] + self.dbm['groups'][group].articles[i].overview())
- return defer.succeed(r)
-
-
- def xhdrRequest(self, group, low, high, header):
- if group not in self.dbm['groups']:
- return defer.succeed([])
-
- if low is None:
- low = 0
- if high is None:
- high = self.dbm['groups'][group].maxArticle
- r = []
- for i in range(low, high + 1):
- if i in self.dbm['groups'][group].articles:
- r.append((i, self.dbm['groups'][group].articles[i].getHeader(header)))
- return defer.succeed(r)
-
-
- def listGroupRequest(self, group):
- if self.dbm['groups'].has_key(group):
- return defer.succeed((group, self.dbm['groups'][group].articles.keys()))
- return defer.fail(NewsServerError("No such group: " + group))
-
-
- def groupRequest(self, group):
- try:
- g = self.dbm['groups'][group]
- except KeyError:
- return defer.fail(NewsServerError("No such group: " + group))
- else:
- flags = g.flags
- low = g.minArticle
- high = g.maxArticle
- num = high - low + 1
- return defer.succeed((group, num, high, low, flags))
-
-
- def articleExistsRequest(self, id):
- return defer.succeed(id in self.dbm['Message-IDs'])
-
-
- def articleRequest(self, group, index, id = None):
- if id is not None:
- try:
- xref = self.dbm['Message-IDs'][id]
- except KeyError:
- return defer.fail(NewsServerError("No such article: " + id))
- else:
- group, index = xref[0]
- index = int(index)
-
- try:
- a = self.dbm['groups'][group].articles[index]
- except KeyError:
- return defer.fail(NewsServerError("No such group: " + group))
- else:
- return defer.succeed((
- index,
- a.getHeader('Message-ID'),
- StringIO.StringIO(a.textHeaders() + '\r\n' + a.body)
- ))
-
-
- def headRequest(self, group, index, id = None):
- if id is not None:
- try:
- xref = self.dbm['Message-IDs'][id]
- except KeyError:
- return defer.fail(NewsServerError("No such article: " + id))
- else:
- group, index = xref[0]
- index = int(index)
-
- try:
- a = self.dbm['groups'][group].articles[index]
- except KeyError:
- return defer.fail(NewsServerError("No such group: " + group))
- else:
- return defer.succeed((index, a.getHeader('Message-ID'), a.textHeaders()))
-
-
- def bodyRequest(self, group, index, id = None):
- if id is not None:
- try:
- xref = self.dbm['Message-IDs'][id]
- except KeyError:
- return defer.fail(NewsServerError("No such article: " + id))
- else:
- group, index = xref[0]
- index = int(index)
-
- try:
- a = self.dbm['groups'][group].articles[index]
- except KeyError:
- return defer.fail(NewsServerError("No such group: " + group))
- else:
- return defer.succeed((index, a.getHeader('Message-ID'), StringIO.StringIO(a.body)))
-
-
-class NewsStorageAugmentation:
- """
- A NewsStorage implementation using Twisted's asynchronous DB-API
- """
-
- implements(INewsStorage)
-
- schema = """
-
- CREATE TABLE groups (
- group_id SERIAL,
- name VARCHAR(80) NOT NULL,
-
- flags INTEGER DEFAULT 0 NOT NULL
- );
-
- CREATE UNIQUE INDEX group_id_index ON groups (group_id);
- CREATE UNIQUE INDEX name_id_index ON groups (name);
-
- CREATE TABLE articles (
- article_id SERIAL,
- message_id TEXT,
-
- header TEXT,
- body TEXT
- );
-
- CREATE UNIQUE INDEX article_id_index ON articles (article_id);
- CREATE UNIQUE INDEX article_message_index ON articles (message_id);
-
- CREATE TABLE postings (
- group_id INTEGER,
- article_id INTEGER,
- article_index INTEGER NOT NULL
- );
-
- CREATE UNIQUE INDEX posting_article_index ON postings (article_id);
-
- CREATE TABLE subscriptions (
- group_id INTEGER
- );
-
- CREATE TABLE overview (
- header TEXT
- );
- """
-
- def __init__(self, info):
- self.info = info
- self.dbpool = adbapi.ConnectionPool(**self.info)
-
-
- def __setstate__(self, state):
- self.__dict__ = state
- self.info['password'] = getpass.getpass('Database password for %s: ' % (self.info['user'],))
- self.dbpool = adbapi.ConnectionPool(**self.info)
- del self.info['password']
-
-
- def listRequest(self):
- # COALESCE may not be totally portable
- # it is shorthand for
- # CASE WHEN (first parameter) IS NOT NULL then (first parameter) ELSE (second parameter) END
- sql = """
- SELECT groups.name,
- COALESCE(MAX(postings.article_index), 0),
- COALESCE(MIN(postings.article_index), 0),
- groups.flags
- FROM groups LEFT OUTER JOIN postings
- ON postings.group_id = groups.group_id
- GROUP BY groups.name, groups.flags
- ORDER BY groups.name
- """
- return self.dbpool.runQuery(sql)
-
-
- def subscriptionRequest(self):
- sql = """
- SELECT groups.name FROM groups,subscriptions WHERE groups.group_id = subscriptions.group_id
- """
- return self.dbpool.runQuery(sql)
-
-
- def postRequest(self, message):
- cleave = message.find('\r\n\r\n')
- headers, article = message[:cleave], message[cleave + 4:]
- article = Article(headers, article)
- return self.dbpool.runInteraction(self._doPost, article)
-
-
- def _doPost(self, transaction, article):
- # Get the group ids
- groups = article.getHeader('Newsgroups').split()
- if not len(groups):
- raise NNTPError('Missing Newsgroups header')
-
- sql = """
- SELECT name, group_id FROM groups
- WHERE name IN (%s)
- """ % (', '.join([("'%s'" % (adbapi.safe(group),)) for group in groups]),)
-
- transaction.execute(sql)
- result = transaction.fetchall()
-
- # No relevant groups, bye bye!
- if not len(result):
- raise NNTPError('None of groups in Newsgroup header carried')
-
- # Got some groups, now find the indices this article will have in each
- sql = """
- SELECT groups.group_id, COALESCE(MAX(postings.article_index), 0) + 1
- FROM groups LEFT OUTER JOIN postings
- ON postings.group_id = groups.group_id
- WHERE groups.group_id IN (%s)
- GROUP BY groups.group_id
- """ % (', '.join([("%d" % (id,)) for (group, id) in result]),)
-
- transaction.execute(sql)
- indices = transaction.fetchall()
-
- if not len(indices):
- raise NNTPError('Internal server error - no indices found')
-
- # Associate indices with group names
- gidToName = dict([(b, a) for (a, b) in result])
- gidToIndex = dict(indices)
-
- nameIndex = []
- for i in gidToName:
- nameIndex.append((gidToName[i], gidToIndex[i]))
-
- # Build xrefs
- xrefs = socket.gethostname().split()[0]
- xrefs = xrefs + ' ' + ' '.join([('%s:%d' % (group, id)) for (group, id) in nameIndex])
- article.putHeader('Xref', xrefs)
-
- # Hey! The article is ready to be posted! God damn f'in finally.
- sql = """
- INSERT INTO articles (message_id, header, body)
- VALUES ('%s', '%s', '%s')
- """ % (
- adbapi.safe(article.getHeader('Message-ID')),
- adbapi.safe(article.textHeaders()),
- adbapi.safe(article.body)
- )
-
- transaction.execute(sql)
-
- # Now update the posting to reflect the groups to which this belongs
- for gid in gidToName:
- sql = """
- INSERT INTO postings (group_id, article_id, article_index)
- VALUES (%d, (SELECT last_value FROM articles_article_id_seq), %d)
- """ % (gid, gidToIndex[gid])
- transaction.execute(sql)
-
- return len(nameIndex)
-
-
- def overviewRequest(self):
- sql = """
- SELECT header FROM overview
- """
- return self.dbpool.runQuery(sql).addCallback(lambda result: [header[0] for header in result])
-
-
- def xoverRequest(self, group, low, high):
- sql = """
- SELECT postings.article_index, articles.header
- FROM articles,postings,groups
- WHERE postings.group_id = groups.group_id
- AND groups.name = '%s'
- AND postings.article_id = articles.article_id
- %s
- %s
- """ % (
- adbapi.safe(group),
- low is not None and "AND postings.article_index >= %d" % (low,) or "",
- high is not None and "AND postings.article_index <= %d" % (high,) or ""
- )
-
- return self.dbpool.runQuery(sql).addCallback(
- lambda results: [
- [id] + Article(header, None).overview() for (id, header) in results
- ]
- )
-
-
- def xhdrRequest(self, group, low, high, header):
- sql = """
- SELECT articles.header
- FROM groups,postings,articles
- WHERE groups.name = '%s' AND postings.group_id = groups.group_id
- AND postings.article_index >= %d
- AND postings.article_index <= %d
- """ % (adbapi.safe(group), low, high)
-
- return self.dbpool.runQuery(sql).addCallback(
- lambda results: [
- (i, Article(h, None).getHeader(h)) for (i, h) in results
- ]
- )
-
-
- def listGroupRequest(self, group):
- sql = """
- SELECT postings.article_index FROM postings,groups
- WHERE postings.group_id = groups.group_id
- AND groups.name = '%s'
- """ % (adbapi.safe(group),)
-
- return self.dbpool.runQuery(sql).addCallback(
- lambda results, group = group: (group, [res[0] for res in results])
- )
-
-
- def groupRequest(self, group):
- sql = """
- SELECT groups.name,
- COUNT(postings.article_index),
- COALESCE(MAX(postings.article_index), 0),
- COALESCE(MIN(postings.article_index), 0),
- groups.flags
- FROM groups LEFT OUTER JOIN postings
- ON postings.group_id = groups.group_id
- WHERE groups.name = '%s'
- GROUP BY groups.name, groups.flags
- """ % (adbapi.safe(group),)
-
- return self.dbpool.runQuery(sql).addCallback(
- lambda results: tuple(results[0])
- )
-
-
- def articleExistsRequest(self, id):
- sql = """
- SELECT COUNT(message_id) FROM articles
- WHERE message_id = '%s'
- """ % (adbapi.safe(id),)
-
- return self.dbpool.runQuery(sql).addCallback(
- lambda result: bool(result[0][0])
- )
-
-
- def articleRequest(self, group, index, id = None):
- if id is not None:
- sql = """
- SELECT postings.article_index, articles.message_id, articles.header, articles.body
- FROM groups,postings LEFT OUTER JOIN articles
- ON articles.message_id = '%s'
- WHERE groups.name = '%s'
- AND groups.group_id = postings.group_id
- """ % (adbapi.safe(id), adbapi.safe(group))
- else:
- sql = """
- SELECT postings.article_index, articles.message_id, articles.header, articles.body
- FROM groups,articles LEFT OUTER JOIN postings
- ON postings.article_id = articles.article_id
- WHERE postings.article_index = %d
- AND postings.group_id = groups.group_id
- AND groups.name = '%s'
- """ % (index, adbapi.safe(group))
-
- return self.dbpool.runQuery(sql).addCallback(
- lambda result: (
- result[0][0],
- result[0][1],
- StringIO.StringIO(result[0][2] + '\r\n' + result[0][3])
- )
- )
-
-
- def headRequest(self, group, index):
- sql = """
- SELECT postings.article_index, articles.message_id, articles.header
- FROM groups,articles LEFT OUTER JOIN postings
- ON postings.article_id = articles.article_id
- WHERE postings.article_index = %d
- AND postings.group_id = groups.group_id
- AND groups.name = '%s'
- """ % (index, adbapi.safe(group))
-
- return self.dbpool.runQuery(sql).addCallback(lambda result: result[0])
-
-
- def bodyRequest(self, group, index):
- sql = """
- SELECT postings.article_index, articles.message_id, articles.body
- FROM groups,articles LEFT OUTER JOIN postings
- ON postings.article_id = articles.article_id
- WHERE postings.article_index = %d
- AND postings.group_id = groups.group_id
- AND groups.name = '%s'
- """ % (index, adbapi.safe(group))
-
- return self.dbpool.runQuery(sql).addCallback(
- lambda result: result[0]
- ).addCallback(
- lambda (index, id, body): (index, id, StringIO.StringIO(body))
- )
-
-####
-#### XXX - make these static methods some day
-####
-def makeGroupSQL(groups):
- res = ''
- for g in groups:
- res = res + """\n INSERT INTO groups (name) VALUES ('%s');\n""" % (adbapi.safe(g),)
- return res
-
-
-def makeOverviewSQL():
- res = ''
- for o in OVERVIEW_FMT:
- res = res + """\n INSERT INTO overview (header) VALUES ('%s');\n""" % (adbapi.safe(o),)
- return res