next up previous contents
Next: Bibliography Up: Clients Previous: Fetch.java   Contents

Biff.java

//Java-based version of xbiff. Biff reads its data off a POP(3)
//server. When Biff is started it regularly contact the POP server and
//beeps when new mail has arrived. It shows the number of messages
//currently on the POP server at the bottom of the
//window. Control-clicking in the window shows a configuration panel
//which allows to change the user, host, password and
//frequency. Single-clicking shows a box with all headers.
//
// - indication of number of mails waiting on POP server
// - listing of headers by single-clicking on the Biff window
// - extension (MailResource) to allow access to a number of other mail
//   resources (e.g. file, IMAP)
//
//Arguments can be seen by starting 'java Biff -help'.
//
//The subjects of all mail currently on the pop server can be looked at
//by clicking with the mouse on Biff's window. A control-mouse-click
//displays a configuration dialog.
//
// example command line:
//java Biff -user daly -pass burns -host pop.mail.net -delay 1000


import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
import java.util.*;
import java.util.Vector;

interface MailListener 
{ public void NewMail(int new_msgs);
  public void Reset();
  public void Error(String msg);
  public void OkAgain();
}

interface MailResource 
{ public void   AddMailListener(MailListener l);
  public void   RemoveMailListener(MailListener l);
  public void   StartPollingForMail();
  public void   StopPollingForMail();
  public Vector GetHeaders() throws Exception;
  public long GetSleepPeriod();
  public void SetSleepPeriod(long msecs);
  public String GetHost();
  public void SetHost(String new_host);
  public String GetUser();
  public void SetUser(String new_user);
  public String GetPass();
  public void SetPass(String new_pass);
}

class PopServer implements MailResource, java.lang.Runnable 
{ private Vector   listeners=new Vector();
  private long     sleep_period=60000;
  private int      counter=0;
  private String   uid="";
  private String   pw="";
  private String   pop_host="popsrv";
  private int      num_msgs=-1;
  private Vector   headers=new Vector();
  private boolean  in_error=false;
  private Thread   poller=null;

  public PopServer(long l, String userid, String password, String popsrv) 
  { sleep_period=l;
    uid=userid;
    pw=password;
    pop_host=popsrv;
    ResetHeaders();
  }

  public long GetSleepPeriod() {return sleep_period;}

  public void SetSleepPeriod(long msecs) 
  { if(msecs > 0) 
      sleep_period=msecs;
  }

  public String GetHost() {return pop_host;}
  public void SetHost(String new_host) {pop_host=new_host;}
  public String GetUser() {return uid;}
  public void SetUser(String new_user) {uid=new_user;}
  public String GetPass() {return pw;}
  public void SetPass(String new_pass) {pw=new_pass;}
    
  public void AddMailListener(MailListener l) 
  { listeners.addElement(l);
  }

  public void RemoveMailListener(MailListener l) 
  { listeners.removeElement(l);
  }

  public void StartPollingForMail() 
  { if(poller == null) 
    { poller=new Thread(this);
      poller.start();
    }
  }

  public synchronized void StopPollingForMail() 
  { if(poller != null) 
    {  poller.stop();
       poller=null;
    }
  }

  public Vector GetHeaders() throws Exception {return headers;}

  private void ResetHeaders() 
  { headers.removeAllElements();
    headers.addElement("      --- No messages available ---   ");
  }

  public void run() 
  { MailListener  l;
    while(true) 
    { try 
      { num_msgs=CheckMail();
        if(in_error == true) 
        { in_error=false;
          for(int i=0; i < listeners.size(); i++)
            ((MailListener)listeners.elementAt(i)).OkAgain();
        }
        if(num_msgs == 0) 
        { if(counter > 0) 
          { for(int i=0; i < listeners.size(); i++)
              ((MailListener)listeners.elementAt(i)).Reset();
            counter=0;
            ResetHeaders();
          }
        }
        else 
        { if(num_msgs > counter) 
          { for(int i=0; i < listeners.size(); i++)
              ((MailListener)listeners.elementAt(i)).NewMail(num_msgs);
            counter=num_msgs;
          }
        }		
      }
      catch(Exception error) 
      { for(int i=0; i < listeners.size(); i++) 
        { in_error=true;
          l=(MailListener)listeners.elementAt(i);
          l.Error("POP server error: " + error);
        }
      }	    
      try 
      { Thread.currentThread().sleep(sleep_period);
      }
      catch(java.lang.InterruptedException ex) 
      { break;
      }
    }
  }

  private String readLn(BufferedReader dis) throws IOException 
  { String incoming;
    StringTokenizer  st;
    incoming=dis.readLine();
    return incoming;
   }

  private boolean popError(String incoming) throws Exception 
  { StringTokenizer st=new StringTokenizer(incoming);
    if((st.nextToken()).equals("-ERR")) 
    { throw new Exception(incoming);
    }
    return false;
  }

  public synchronized int CheckMail() throws Exception 
  { Socket            talk=null;
    BufferedReader    inp=null;
    DataOutputStream  outs=null;
    StringTokenizer   st;
    StringBuffer      header;
    int               num_msgs=-1;
    String            toss, line;
    try 
    { talk=new Socket(pop_host,110);
      inp=new BufferedReader(new InputStreamReader(talk.getInputStream()));
      outs=new DataOutputStream(talk.getOutputStream());
      PrintWriter p = new PrintWriter(talk.getOutputStream());
      popError(readLn(inp));
      Thread.currentThread().sleep(1000); 
      p.println("user "+uid); p.flush();
      popError(readLn(inp));
      p.println("pass "+pw); p.flush();
      popError(readLn(inp));
      p.println("stat"); p.flush();
      toss=readLn(inp);
      popError(toss);
      st=new StringTokenizer(toss);
      st.nextToken();
      num_msgs=Integer.parseInt(st.nextToken());
      if(num_msgs > counter) 
      { headers.removeAllElements();
        for(int i=1; i < num_msgs+1; i++) 
        { header=new StringBuffer();		
          outs.writeBytes("top " + i + " 0\n");
          popError(readLn(inp));
          while(true) 
          { line=readLn(inp);
            if(line.equals(".") || line == null)
              break;
            if(line.indexOf("From:") != -1) 
            { header.append(line);
              continue;
            }
            if(line.indexOf("Subject:") != -1) 
            { header.append(" " + line);
              continue;
            }
          }
          if(header.length() > 0)
            headers.addElement(header.toString());
        }	    	    
      }
      outs.writeBytes("QUIT\n");
      outs.flush();
      outs.close();
      outs=null;
    } 
    catch (Exception e) 
    { if(outs != null) 
      { outs.writeBytes("QUIT\n");
        outs.flush();
        outs.close();
        outs=null;
      }
      throw e;
    }
    finally 
    { if(outs != null) 
      { outs.writeBytes("QUIT\n");
        outs.flush();
        outs.close();
        outs=null;
      }
      if(talk != null)
        talk.close();	    
      if(headers.size() == 0)
        ResetHeaders();
    }
    return num_msgs;
  }
}

class Headers extends Window 
{
 public Headers(Frame parent, Vector vec) 
 { super(parent);
   java.awt.List headers=new java.awt.List();
   for(int i=0; i < vec.size(); i++) 
   { headers.add((String)vec.elementAt(i));
   }
   headers.addMouseListener(
     new MouseListener() 
     { public void mouseClicked(MouseEvent e) {Close();}
       public void mouseEntered(MouseEvent e) {}
       public void  mouseExited(MouseEvent e) {}
       public void mousePressed(MouseEvent e) {}
       public void mouseReleased(MouseEvent e) {}
     }
   );
   add(headers);
   setSize(500,300);
   Point parent_loc=parent.getLocation();
   parent_loc.x=parent_loc.x-430;
   setLocation(parent_loc);
   setFont(new Font("TimesRoman",Font.BOLD,12));
   show();
 }

 public void Close() {dispose();}

}

class bCanvas extends Canvas 
{ Image      one=null, two=null;
  Toolkit    tk;
  Biff       jb;
  Graphics   offgraph;
  Image      offscrn;
    
  public bCanvas(Biff jb) 
  { super();
    File f1test, f2test;
    this.jb = jb;
    try 
    { f1test = new File(this.jb.mail);
      f2test = new File(this.jb.nomail);
      tk=this.getToolkit();
      if(f1test.exists())
        one=tk.getImage(this.jb.mail); 
      if(f2test.exists())
        two=tk.getImage(this.jb.nomail); 
    } 
    catch (NullPointerException e) 
    { System.err.println("File is null");
    }
  }

  public void paint(Graphics g) 
  { Dimension    dm;
    FontMetrics  fm;
    dm=jb.size();
    offscrn = createImage(this.size().width,this.size().height);
    offgraph = offscrn.getGraphics();
    offgraph.setColor(Color.lightGray);
    if (one==null)
      offgraph.draw3DRect(0,0,this.size().width,this.size().height, true);
    offgraph.setColor(Color.black);
    if(jb.ErrorOccurred()) 
    { offgraph.setColor(Color.red);
      offgraph.setFont(new Font("TimesRoman",Font.BOLD,12));
      fm=getFontMetrics(new Font("TimesRoman",Font.BOLD,12));
      offgraph.drawString("  Error  ",
        (this.size().width - fm.stringWidth("  Error  "))/2,
        ((this.size().height) - (fm.getHeight()/2)));	    
      g.drawImage(offscrn,0,0,this);
      return;
    }
    if(jb.num_msgs > 0) 
    { if (one!=null) 
      {	offgraph.drawImage(one,0,0,dm.width,dm.height-50,this);
        offgraph.setFont(new Font("TimesRoman",Font.BOLD,12));
        fm=getFontMetrics(new Font("TimesRoman", Font.BOLD,12));
        offgraph.drawString(" " + jb.num_msgs + " msg",
          (this.size().width - fm.stringWidth("     "))/2-10,
          ((this.size().height) - (fm.getHeight()/2))+5);	
      }
      else 
      { offgraph.setColor(Color.blue);
        offgraph.fillRect(0,0,dm.width,dm.height);
        offgraph.setColor(Color.white);
        offgraph.setFont(new Font("TimesRoman",Font.BOLD,12));
        fm=getFontMetrics(new Font("TimesRoman", Font.BOLD,12));
        offgraph.drawString(" " + jb.num_msgs + " msg",
          (this.size().width - fm.stringWidth("     "))/2,
          ((this.size().height) - (fm.getHeight()/2)));	
      }
    }
    else 
    { offgraph.setColor(Color.black);
      if (two!=null) 
      { offgraph.drawImage(two,0,0,dm.width,dm.height,this);
      } 
      else 
      { offgraph.setFont(new Font("TimesRoman",Font.BOLD,12));
        fm=getFontMetrics(new Font("TimesRoman",Font.BOLD,12));
        offgraph.drawString(" No Mail ",
          (this.size().width - fm.stringWidth(" No Mail "))/2,
          ((this.size().height) - (fm.getHeight()/2)));
      }
    }
    g.drawImage(offscrn,0,0,this);
  }

  public void update(Graphics g) {paint(g);}
    
  public Dimension preferredSize() {return new Dimension(70,70);}
    
  public Dimension minimumSize() {return preferredSize();}
}	

class bInfoBox extends Frame 
{ Biff caller;

  public bInfoBox(String title,String message, Biff caller) 
  { super(title);
    this.caller = caller;
    add("Center",new Label(message,Label.CENTER));
    Button okay = new Button("Okay");
    add("South",okay);
    pack();
    show();
  }
    
  public boolean handleEvent(Event evt) 
  { if ( evt.target instanceof Button) 
    { this.dispose();
      caller.killjberror();
      return true;
    }
    return super.handleEvent(evt);
  }
}

class bSetup extends Frame 
{ TextField mailhost,user,pass,freq;
  Button close,reset,quit;
  Biff jb;
  bInfoBox info;
	
  public bSetup(Biff jb)
  { super("Biff Configure");
    this.jb= jb;
    setLayout(new GridLayout(5,1,10,10));
    Panel line1 = new Panel();
    Panel line2 = new Panel();
    Panel line3 = new Panel();
    Panel line4 = new Panel();
    Panel line5 = new Panel();
    line1.setLayout(new GridLayout(1,2,5,5));
    line2.setLayout(new GridLayout(1,2,5,5));
    line3.setLayout(new GridLayout(1,2,5,5));
    line4.setLayout(new GridLayout(1,3,5,5));
    line5.setLayout(new GridLayout(1,2,5,5));
    line1.add(new Label("Mailhost:",Label.RIGHT));
    mailhost = new TextField(jb.GetHost(),30);		
    line1.add(mailhost);
    line2.add(new Label("User Name:",Label.RIGHT));
    user = new TextField(jb.GetUser(),30);
    line2.add(user);
    line3.add(new Label("Password:",Label.RIGHT));
    pass = new TextField(jb.GetPass(),15);
    pass.setEchoCharacter('*');
    line3.add(pass);
    line5.add(new Label("Frequency (milliseconds):",Label.RIGHT));
    freq = new TextField(Long.toString(jb.GetDelay()),2);
    line5.add(freq);
    close = new Button("Set Values");
    quit = new Button("Quit");
    line4.add(close); 
    line4.add(quit); 
    add(line1);
    add(line2);
    add(line3);
    add(line5);
    add(line4);
    pack();
  }

  public boolean handleEvent (Event evt) 
  { if (evt.target == close) 
    { jb.SetUser(user.getText());
      jb.SetPass(pass.getText());
      jb.SetHost(mailhost.getText());
      try 
      { jb.SetDelay(Integer.parseInt(freq.getText()));
      } 
      catch (NumberFormatException e) {};
      setVisible(false);
      return true;
    }
    if (evt.target == reset) 
    { jb.jbcanvas.repaint();
      return true;
    }
    if (evt.target == quit) 
    { System.exit(0);
      return true;
     }
     return false;
   }
 }

 public class Biff extends Frame implements MailListener, WindowListener 
 { bSetup jbsetup;
   bCanvas jbcanvas;
   String nomail,mail;
   bInfoBox jberror;
   int num_msgs=0;
   MailResource mail_resource=null;
   Headers headers=null;
   boolean error_occurred=false;
	
   public Biff(String title,String m,String n, MailResource res) 
   { super(title);
     mail = m; 
     nomail =n;
     mail_resource=res;
     jbsetup = new bSetup(this);
     jbcanvas = new bCanvas(this);
     add("Center",jbcanvas);
     pack();
     setSize(70,90);
     mail_resource.AddMailListener(this);
     mail_resource.StartPollingForMail();
     addWindowListener(this);
     show();
   }

   public long   GetDelay() {return mail_resource.GetSleepPeriod();}
   public void   SetDelay(long msecs) {mail_resource.SetSleepPeriod(msecs);}
   public String GetHost() {return mail_resource.GetHost();}
   public void   SetHost(String new_host) {mail_resource.SetHost(new_host);}
   public String GetUser() {return mail_resource.GetUser();}
   public void   SetUser(String new_user) {mail_resource.SetUser(new_user);}
   public String GetPass() {return mail_resource.GetPass();}
   public void   SetPass(String new_pass) {mail_resource.SetPass(new_pass);}
   public boolean ErrorOccurred() {return error_occurred;}
   public void killjberror(){jberror=null;}
	
   public boolean handleEvent (Event evt) 
   { if (evt.id ==  Event.MOUSE_DOWN) 
     { if(evt.controlDown()) 
       { jbsetup.show();
         return true;
       }
       else 
       { try 
         { headers=new Headers(this, mail_resource.GetHeaders());
         }
         catch(Exception e) {}
         return true;
       }
     }
     return super.handleEvent(evt);
   }

   public void NewMail(int num_new_msgs) 
   { error_occurred=false;
     Toolkit.getDefaultToolkit().beep();
     num_msgs=num_new_msgs;
     jbcanvas.repaint();	
   }

   public void Reset() 
   { error_occurred=false;
     num_msgs=0;
     jbcanvas.repaint();
   }

   public void Error(String msg) 
   { error_occurred=true;
     System.err.println(msg);
     jbcanvas.repaint();
   }

   public void OkAgain() 
   { error_occurred=false;
     jbcanvas.repaint();
   }

   public void windowOpened(WindowEvent e) {}
   public void windowClosing(WindowEvent e) 
   { mail_resource.RemoveMailListener(this);
     mail_resource.StopPollingForMail();
     System.exit(1);
   }
   public void windowClosed(WindowEvent e) {}
   public void windowIconified(WindowEvent e) {}    
   public void windowDeiconified(WindowEvent e) {}
   public void windowActivated(WindowEvent e) {}
   public void windowDeactivated(WindowEvent e) {}

   public static void main(String args[]) 
   { Biff master;
     long d=60000;
     String m ="";
     String n ="";
     String p ="";
     String u ="user";
     String h ="host";
     for(int i = 0; i < args.length; i++) 
     { if (args[i].equals("-mail")) m =args[i+1];	
       if (args[i].equals("-nomail")) n =args[i+1];	
       if (args[i].equals("-pass")) p = args[i+1];
       if (args[i].equals("-user")) u = args[i+1];
       if (args[i].equals("-host")) h = args[i+1];
       if (args[i].equals("-delay")) d = new Long(args[i+1]).longValue();
       if (args[i].equals("-help")){
       System.out.println("\nBiff -- Biff for Java");
       System.out.println("Mouse click -- see headers");
       System.out.println("Control-mouse click -- change parameters/quit");
       System.out.println("  -mail filename ");
       System.out.println("  -nomail filename ");
       System.out.println("  -user username");
       System.out.println("  -pass password");
       System.out.println("  -host mailhost");
       System.out.println("  -delay milliseconds");
       System.out.println("  --help\n\n");
       System.exit(0);
     }
   }
   MailResource res=new PopServer(d, u, p, h);
   master = new Biff("Biff",m,n,res);
   Dimension dim=Toolkit.getDefaultToolkit().getScreenSize();
   master.setLocation(dim.width-70, 65);
 }
}


root 2004-03-16