#  PMail - GNOME/GTK/Python email client
#  Copyright (C) 2000 Scott Bender <sbender@harmony-ds.com>

#  This file is part of PMail.

#  PMail is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2, or (at your option)
#  any later version.

#  PMail is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.

#  You should have received a copy of the GNU General Public License
#  along with GNU Emacs; see the file COPYING.  If not, write to
#  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
#  Boston, MA 02111-1307, USA.  

import string
import rfc822
import mimetools
import time
import mhlib
import os
import posixfile
from StringIO import StringIO

from Base import *
import Mailbox
import Message
import Source
import config
import util
import pmailmailbox


class SpoolFileSource(Source.Source):
  def __init__(self, path=None):
    Source.Source.__init__(self)

    user_name = util.get_user_name()
    if not path:
      path = '/usr/spool/mail/' + user_name
      if not os.path.exists(path):
        path = '/var/spool/mail/' + user_name
    
    self._path = path
    self._deleteOption = Source.MARK
    
    self.add_config_params(['path', 'deleteOption'])

  def name(self):
    return not self._display_name and \
           '{SPOOL}%s' % self._path \
           or self._display_name

  def can_add_subfolder(self):
    return false

  def can_delete(self):
    return false

  def can_rename(self):
    return false

  def can_expunge(self):
    return false

  def mailboxes(self):
    if not self._mailboxes:
      self._mailbox = SpoolFileMailbox(self, self._path)
      self._mailboxes = {self._path: self._mailbox}
    return self._mailboxes and self._mailboxes.values() or None

  def _get_body(self, mailbox, uid, part_number=''):
    return mailbox._get_body(mailbox, uid, part_number)

  def delete_message(self, message):
    return mailbox.delete()

  def unseen_count(self, mailbox):
    return mailbox.unseen_count()

  def message_count(self, mailbox):
    return mailbox.message_count()

  def _get_messages(self, mailbox):
    return mailbox._get_messages()

class SpoolFileMailbox(Mailbox.Mailbox):
  def __init__(self, source, path, delim ='/', parent = None):
    Mailbox.Mailbox.__init__(self, source, parent)
    self._path = path
    self._uid_map = {}
    self._last_read_time = None
    self._fp = None

    try:
      idx = string.rindex(path, delim)
      self._name = path[idx+1:]
    except ValueError:
      self._name = path

    self.init_done()

  def path(self):
    return self._path

  def check_mail(self, changes=None):
    Mailbox.Mailbox.check_mail(self, changes)
    return self.sync_messages()

  def expunge(self):
    #deleted = filter(lambda x: x.deleted(), self._messages)
    #foreach(self._source._really_delete_message, deleted)
    #subtract_lists(self._messages, deleted)
    pass

  def save_message_cache(self, dir):
    pass

  def load_message_cache(self, dir):
    return 0

  def _get_body(self, mailbox, uid, part_number=''):
    return None
    
  def delete(self):
    pass

  def unseen_count(self):
    return 0

  def message_count(self):
    self.messages()
    return len(self._messages)

  def sync_messages(self):
    t = os.path.getmtime(self._path)
    if not self._last_read_time \
       or t > self._last_read_time:
      print 'reloading messages'
      self._get_messages()
      return 1
    print 'no new messages'
    return 0

  def _equal_headers(self, left, right):
    for key, val in left.dict.items():
      #ignore status changes
      if key != 'status' and key != 'x-status' and val != right.dict.get(key):
        return 0
    return 1

  def _get_messages(self):
    try:
      self._last_read_time = os.path.getmtime(self._path)
      f = open(self._path, "r")
      mb = pmailmailbox.UnixMailbox(f)
      messages = []

      idx = 1
      while 1:
        h = mb.next()
        if not h:
          break
        msg = SpoolFileMessage(self._source, self, idx, h)
        msg.get_parts()
        msg.body()
        msg.fp = None
        messages.append(msg)
        idx = idx + 1
        
      f.close()
      self._messages = messages
    except IOError, x:
      self._messages = []
    except OSError, x:
      self._messages = []

    return self._messages

  def sync_messages(self):
    try:
      t = os.path.getmtime(self._path)
      if self._last_read_time \
         and t == self._last_read_time:
        return 0
      
      self._last_read_time = t
      f = posixfile.open(self._path, "r")
      f.lock('r|', 0, posixfile.SEEK_END)
      mb = pmailmailbox.UnixMailbox(f)
      messages = []

      idx = 0
      midx = 0
      while 1:
        h = mb.next()
        if not h:
          break
        cur = midx < len(self._messages) and self._messages[midx] or None

        msg = None
        while 1 and cur:
          if not self._equal_headers(cur._headers, h):
            midx = midx + 1
            cur = midx < len(self._messages) and self._messages[midx] or None
          else:
            msg = cur
            msg._id = idx
            cur._headers.dict['status'] = h.getheader('status')
            cur._headers.dict['x-status'] = h.getheader('x-status')
            cur._update_flags()
            midx = midx + 1
            break

        if not msg:
          msg = SpoolFileMessage(self._source, self, idx+1, h)
          msg.get_parts()
          msg.body()
          msg.fp = None
          
        messages.append(msg)
          
        idx = idx + 1

      f.lock('u')
      f.close()
      self._messages = messages
    except IOError, x:
      self.log_error('IOError: %s' % x)
      self._messages = []
    except OSError, x:
      self.log_error('IOError: %s' % x)
      self._messages = []

    return self._messages
  
    
class SpoolFileMessage(Message.Message):
  def __init__(self, source, mailbox, id, hdrs, flags=None):
    Message.Message.__init__(self, source, mailbox, id, hdrs, flags)
    #self._debug = 0
    mailbox._uid_map[id] = self

    self._update_flags()

    self._date = hdrs.getdate('date')
    self._float_date = time.mktime(self._date)

  def _update_flags(self):
    status = self._headers.getheader('status')
    xstatus = self._headers.getheader('x-status')
    self._flags = {}
    self._flags['seen'] = string.find(status, 'R') != -1
    if xstatus:
      self._flags['deleted'] = string.find(xstatus, 'D') != -1
      self._flags['answered'] = string.find(xstatus, 'A') != -1
      self._flags['flagged'] = string.find(xstatus, 'F') != -1
    
  def get_parts(self):
    if self._parts == None:
      self._parts = Message.make_mimeparts(self._headers, self)
      if self._debug:
        self._parts._dump()
    return self._parts
  
  def body(self):
    if not self._body:
      self._body = self._headers.getbodytext()
    return self._body

  def load_all_headers(self):
    return self._headers

  def full_body(self):
    return self.body()
