#!/usr/local/bin/python

import sys, os, string, time, socket
import nntplib, rfc822

NNTPSERVER = "ca.news.verio.net"
PATH = os.path.expanduser("~/News/")

def exceptionString():
  import StringIO, traceback

    ## get the traceback message  
  sfp = StringIO.StringIO()
  traceback.print_exc(file=sfp)
  exception = sfp.getvalue()
  sfp.close()
  return exception

class FetchNews:
  def __init__ (self, server, path):
    self._server = server
    self._rc = os.path.expanduser("~/.fetchnews-%s" % server)
    self._read = {}
    self._path = path
    self._cur_filename = None
    self._cur_fp = None

  def lock (self):
    lock_file = "%s.lock" % self._rc
    if os.path.exists(lock_file):
      raise Locked, "Lock Exists"
    pid = os.getpid()
    fp = open(lock_file, 'w')
    fp.write("%s" % pid)
    fp.close()

  def unlock (self):
    lock_file = "%s.lock" % self._rc
    try:
      os.unlink(lock_file)
    except:
      pass

  def load_rc (self):
    fp = open (self._rc)
    while 1:
      line = fp.readline()
      if not line: break
      line = string.strip(line)
      if line[0] == '#': continue
      (group, last) = string.split (line, ':', 1)
      self._read[group] = int(last)

  def save_rc (self):
    fp = open (self._rc, 'w')
    for (group, last) in self._read.items():
      fp.write("%s: %s\n" % (group, last))
    fp.close()

  def output_file (self, group, date):
    date_str = time.strftime("%Y-%m", date)
    new_filename = os.path.join (self._path, "%s.%s" % (group, date_str))
    if new_filename != self._cur_filename:
      self._cur_filename = new_filename
      self._cur_fp = open(self._cur_filename, 'a')
      latest_date_str = time.strftime("%Y-%m", time.localtime(time.time()))
      if latest_date_str == date_str:
        latest_fn = os.path.join (self._path, "%s.latest" % (group))
	try:
	  os.unlink (latest_fn)
	except os.error:
	  pass
        os.symlink (new_filename, latest_fn)
    return self._cur_fp

  def update_group (self, group, lastread):
    lastread = int(lastread)
    s = nntplib.NNTP(self._server)
    (resp, count, first, last, name) = s.group(group)
    first = int(first)
    last = int(last)
    if first > lastread: lastread = first
    if lastread >= last: return
    sys.stdout.write("XOVER %s %d-%d\n" % (group, lastread, last))
    (resp, arts) = s.xover(str(lastread+1), str(last))
    host = socket.gethostname()
    for (num, subj, poster, date, id, ref, size, lines) in arts:
      if lines and int(lines) < 100: continue
      if string.find(subj, ".jpg") != -1: continue
      if string.find(subj, ".gif") != -1: continue
      try:
        post = s.article(num)
        tdate = rfc822.parsedate(date)
        author = rfc822.parseaddr(poster)
        fp = self.output_file(group, tdate)
        fp.write("From %s %s\n" % (author[1], time.asctime(tdate)))
        time_str = time.strftime("%a, %d %b %Y %H:%M:%S %Z", time.localtime(time.time()))
        fp.write("Received: from %s by %s with NNTP; %s\n" % (self._server, host, time_str))
        fp.write(string.join(post[3], '\n'))
        fp.write("\n\n")
        sys.stdout.write("%s\r" % num)
      except:
        sys.stderr.write("%s\n" % exceptionString())
        sys.stderr.write("Unable to handle post %s, skipping...\n" % num)
    self._read[group] = last

  def update (self):
    self.lock()
    self.load_rc()
    for (group, last) in self._read.items():
      self.update_group (group, last)
      self.save_rc()
    self.unlock()
  
def main(argv):
  fn = FetchNews(NNTPSERVER, PATH)
  fn.update()

if __name__ == "__main__":
  main (sys.argv)
