#
# mailp.y
#
#   Copyright (c) 1999 Minero Aoki <aamine@dp.u-netsurf.ne.jp>
#
#   This program is free software.
#   You can distribute/modify this program under the terms of
#   the GNU Library General Public License.
#

class Mailp

rule

  content:

      DateH         datetime   { @field.date  = val[1] }
    | RecvH         received
    | RetpathH      returnpath
    | MaddrH        addrs      { @field.addrs.replace val[1] }
    | SaddrH        addr       { @field.addr  = val[1] }
    | MmboxH        mboxes     { @field.addrs.replace val[1] }
    | SmboxH        mbox       { @field.addr  = val[1] }
    | MsgidH        msgid      { @field.msgid = val[1] }
    | RefH          refs       { @field.refs.replace val[1] }
    | KeyH          keys       { @field.keys.replace val[1] }
    | EncH          enc
    | VersionH      version
    | CTypeH        ctype
    | CEncodingH    cencode
    | CDispositionH cdisp
    | Mbox          mbox
      {
        mb = val[1]
        @field.phrase = mb.phrase
        @field.setroute mb.route
        @field.local  = mb.local
        @field.domain = mb.domain
      }
    | Spec          spec
      {
        mb = val[1]
        @field.local  = mb.local
        @field.domain = mb.domain
      }
    ;
  
  datetime: day DIGIT ATOM DIGIT hour zone
    #       0   1     2    3     4    5
    #           day  month year
    {
      t = Time.gm( val[3].to_i, val[2], val[1].to_i, 0, 0, 0 )
      result = (t + val[4] - val[5]).localtime
    }
    ;
  
  day:  /* none */
    | ATOM ','
    ;
  
  hour: DIGIT ':' DIGIT
      { result = (result.to_i * 60 * 60) + (val[2].to_i * 60) }
    | DIGIT ':' DIGIT ':' DIGIT
      { result = (result.to_i * 60 * 60) + (val[2].to_i * 60) + val[4].to_i }
    ;
  
  zone: ATOM { result = ::TMail.zonestr2i( val[0] ) * 60 }
    ;
  
  received: from by via with id for recvdatetime
      {
        @field.from  = val[0] if val[0]
        @field.by    = val[1] if val[1]
        @field.via   = val[2] if val[2]
        @field.with.replace val[3]
        @field.msgid = val[4] if val[4]
        @field.for_  = val[5] if val[5]
        @field.date  = val[6] if val[6]
      }
    ;

  from: /* none */
    | FROM domain
      {
        result = val[1].join('.')
      }
    | FROM domain '@' domain
      {
        result = val[3].join('.')
      }
    | FROM domain DOMLIT
      {
        result = val[1].join('.')
      }
    ;
  
  by:  /* none */
    | BY domain
      {
        result = val[1].join('.')
      }
    ;
  
  via:  /* none */
    | VIA ATOM
      {
        result = val[1]
      }
    ;
  
  with:  /* none */
      {
        result = []
      }
    | with WITH ATOM
      {
        result.push val[2]
      }
    ;
  
  id:  /* none */
    | ID msgid
      {
        result = val[1]
      }
    | ID ATOM
      {
        result = val[1]
      }
    ;
  
  for:  /* none */
    | FOR addr { result = val[1].address }
    ;
  
  recvdatetime:  /* none */
    | ';' datetime { result = val[1] }
    ;
  
  returnpath: '<' '>'
    | routeaddr
      {
        @field.route.replace result.route
        @field.addr = result.addr
      }
    ;

  addrs: addr        { result = val }
    | addrs ',' addr { result.push val[2] }
    ;

  addr: mbox | group ;

  mboxes: mbox        { result = val }
    | mboxes ',' mbox { result.push val[2] }
    ;

  mbox: spec
    | routeaddr
    | phrase routeaddr
      {
        val[1].phrase = HFdecoder.decode( result )
        result = val[1]
      }
    ;

  group: phrase ':' mboxes ';' { result = AddressGroup.new( result, val[2] ) }
    ;

    # |    phrase ':' ';' { result = AddressGroup.new( result ) }
  
  routeaddr: '<' route spec '>'
      {
        result = val[2]
        result.route = val[1]
      }
    | '<' spec '>'
      {
        result = val[1]
      }
    ;
  
  route: at_domains ':' ;
  
  at_domains: '@' domain        { result = [ val[1] ] }
    | at_domains ',' '@' domain { result.push val[3] }
    ;
  
  spec: local '@' domain { result = Address.new( val[0], val[2] ) }
    | local              { result = Address.new( result, nil ) }
    ;
  
  local: word
      {
        result = val
      }
    | local '.' word
      {
        result.push val[2]
      }
    ;
  
  domain: domword
      {
        result = val
      }
    | domain '.' domword
      {
        result.push val[2]
      }
    ;

  domword: atom
    | DOMLIT
    | DIGIT
    ;

  msgid: '<' spec '>'
      {
        val[1] = val[1].addr
        result = val.join('')
      }
    ;
  
  phrase: word
    | phrase word { result << ' ' << val[1] }
    ;
  
  word: atom
    | QUOTED
    | DIGIT
    ;

  keys: phrase
    | keys ',' phrase
    ;
  
/*
  now using normal code

  refs:        { result = [] }
    | refs ref { result.push val[1] }
    ;

  ref: phrase | msgid ;
*/

  enc: word
      {
        @field.encrypter = val[0]
      }
    | word word
      {
        @field.encrypter = val[0]
        @field.keyword   = val[1]
      }
    ;

  version: DIGIT '.' DIGIT
      {
        @field.major = val[0].to_i
        @field.minor = val[2].to_i
      }
    ;

  ctype: TOKEN '/' TOKEN params
      {
        @field.main = val[0]
        @field.sub  = val[2]
      }
    | TOKEN params
      {
        @field.main = val[0]
        @field.sub  = ''
      }
    ;
  
  params: /* none */
    | params ';' TOKEN '=' value
      {
        @field.params[ val[2].downcase ] = val[4]
      }
    ;

  value: TOKEN | QUOTED ;

  cencode: TOKEN { @field.encoding = val[0] }
    ;

  cdisp: TOKEN disp_params { @field.disposition = val[0] }
    ;
  
  disp_params:  /* none */
    | disp_params ';' disp_param
    ;

  disp_param:
    | TOKEN '=' value  { @field.params[ val[0].downcase ] = val[2] }
    ;
  
  atom: ATOM | FROM | BY | VIA | WITH | ID | FOR ;
  
end


---- header = tab.head.rb
---- inner  = tab.inner.rb
---- footer = tab.foot.rb
