View Javadoc

1   package de.tivsource.lib.jcyradm;
2   
3   import java.io.BufferedReader;
4   import java.io.FileInputStream;
5   import java.io.IOException;
6   import java.io.InputStream;
7   import java.io.InputStreamReader;
8   import java.io.PrintStream;
9   import java.math.BigDecimal;
10  import java.net.Socket;
11  import java.util.HashMap;
12  import java.util.Locale;
13  import java.util.Map;
14  import java.util.Properties;
15  import java.util.ResourceBundle;
16  import java.util.regex.Pattern;
17  
18  import javax.net.ssl.SSLSocket;
19  import javax.net.ssl.SSLSocketFactory;
20  
21  import org.apache.log4j.Logger;
22  
23  import de.tivsource.lib.jcyradm.exception.AuthenticationFailure;
24  import de.tivsource.lib.jcyradm.exception.MailboxExists;
25  import de.tivsource.lib.jcyradm.exception.NoLogMessagesFile;
26  import de.tivsource.lib.jcyradm.exception.NoMailbox;
27  import de.tivsource.lib.jcyradm.exception.NoPropertiesFile;
28  import de.tivsource.lib.jcyradm.exception.NoQuota;
29  import de.tivsource.lib.jcyradm.exception.NoServerAnswerFile;
30  import de.tivsource.lib.jcyradm.exception.NoServerResponse;
31  import de.tivsource.lib.jcyradm.exception.NoServerStream;
32  import de.tivsource.lib.jcyradm.exception.NoValidMailboxName;
33  import de.tivsource.lib.jcyradm.exception.QuotaNotInitialized;
34  import de.tivsource.lib.jcyradm.exception.UnexpectedExtraArguments;
35  import de.tivsource.lib.jcyradm.exception.UnexpectedServerAnswer;
36  
37  /**
38   * JCyrAdm ist eine Libary die dazu dient eine Verbindung mit einem
39   * Cyrus-Imap-Server herzustellen und um dann Verwaltungsoperationen
40   * auszuführen (createMailbox, removeMailbox, etc. ).
41   *
42   * @author Marc Michele
43   *
44   */
45  public class JCyrAdm {
46  
47      /**
48       * Statischer Logger der Klasse JCyrAdm, zur Zeit gibt es Meldungen vom
49       * Type INFO, TRACE und DEBUG.
50       */
51      private static final Logger LOGGER = Logger.getLogger(JCyrAdm.class);
52  
53      /**
54       * Der Standard Imap-Port.
55       */
56      private static final int DEFAULT_IMAP_PORT = 143;
57  
58      /**
59       * Der Standard Imap-SSL-Port.
60       */
61      private static final int DEFAULT_IMAP_SSL_PORT = 993;
62  
63      /**
64       * Die Standard Properties Datei.
65       */
66      private static final String DEFAULT_PROPERTIES_FILE = "jcyradm.properties";
67  
68      /**
69       * Cyrus Imap-Host zu dem die Verbindung aufgebaut werden soll.
70       */
71      private String host = "localhost";
72  
73      /**
74       * Port auf dem der Cyrus Server lauscht.
75       */
76      private Integer port;
77  
78      /**
79       * Default ACL.
80       */
81      private String allacl = "lrswipcda";
82  
83      /**
84       * Administrator mit dem die Verbindung aufgebaut werden soll.
85       */
86      private String administrator;
87  
88      /**
89       * Passwort des Administrators.
90       */
91      private String password;
92  
93      /**
94       * Belegter Speicherplatz der Mailbox.
95       */
96      private BigDecimal used;
97  
98  
99      /**
100      * Zugeordneter Speicherplatz der Mailbox.
101      */
102     private BigDecimal quota;
103 
104     /**
105      * Prozentuale Belegung der Mailbox.
106      */
107     private BigDecimal load;
108 
109     /**
110      * Willkommens-Nachricht des Servers.
111      */
112     private String welcomeMsg;
113 
114     /**
115      * SSL-Socket-Verbindungs-Objekt.
116      */
117     private SSLSocket sslRequestSocket;
118 
119     /**
120      * Socket-Verbindungs-Objekt.
121      */
122     private Socket requestSocket;
123 
124     /**
125      * Der Stream mit dem zu Server geschrieben wird.
126      */
127     private PrintStream out;
128 
129     /**
130      * Der Stream mit dem vom Server gelesen wird.
131      */
132     private BufferedReader in;
133 
134     /**
135      * Map mit den ACLs der aktuellen Mailbox (User/ACL).
136      */
137     private Map<String, String> acls;
138 
139     /**
140      * Map mit den Rückgabewerten des ID Kommandos.
141      */
142     private Map<String, String> idMap = new HashMap<String, String>();
143 
144     /**
145      * Property Datei in der die Einstellungen gespeichert werden.
146      */
147     private Properties props;
148 
149     /**
150      * Datei mit den erwarteten Server-Anworten.
151      */
152     private ResourceBundle serverAnswers;
153 
154     /**
155      * Datei mit den Log-Nachrichten.
156      */
157     private ResourceBundle logMessages;
158 
159     /**
160      * Standard Konstruktor der Klasse JCyrAdm, dabei wird die interne
161      * Properties-Datei benutzt.
162      *
163      * @throws NoPropertiesFile - Ausnahme wenn die Properties-Datei nicht
164      *             gefunden wird.
165      * @throws NoServerAnswerFile
166      * @throws NoLogMessagesFile
167      */
168 	public JCyrAdm() throws NoPropertiesFile, NoServerAnswerFile,
169 			NoLogMessagesFile {
170         super();
171         LOGGER.debug("Aktuelle Sprache: " + Locale.getDefault().getLanguage());
172         props = new Properties();
173 
174         try {
175             LOGGER.debug("Lade Standard Properties Datei.");
176             InputStream inputStream = getClass().getClassLoader()
177                     .getResourceAsStream(DEFAULT_PROPERTIES_FILE);
178             props.load(inputStream);
179             inputStream.close();
180         } catch (Exception e1) {
181             throw new NoPropertiesFile();
182         }
183 
184         try {
185             LOGGER.debug("Lade Server Antworten Datei.");
186             serverAnswers = ResourceBundle.getBundle("server");
187         } catch (Exception e2) {
188             throw new NoServerAnswerFile();
189         }
190 
191         try {
192             LOGGER.debug("Lade Log-Nachrichten Datei.");
193             logMessages = ResourceBundle.getBundle("logging");
194         } catch (Exception e3) {
195             throw new NoLogMessagesFile();
196         }
197 
198     } // Ende JCyrAdm()
199 
200     /**
201      * Konstruktor der Klasse JCyrAdm, es muss eine Properties-Datei angegeben
202      * werden.
203      *
204      * @param properties - Properties-Datei
205      * @throws NoPropertiesFile - Ausnahme wenn die Properties-Datei nicht
206      *             gefunden wird.
207      * @throws NoServerAnswerFile
208      * @throws NoLogMessagesFile
209      */
210 	public JCyrAdm(String properties) throws NoPropertiesFile,
211 			NoServerAnswerFile, NoLogMessagesFile {
212         super();
213         LOGGER.debug("Aktuelle Sprache: " + Locale.getDefault().getLanguage());
214         props = new Properties();
215 
216         try {
217             LOGGER.debug("Lade Properties Datei.");
218             InputStream inputStream = new FileInputStream(properties);
219             props.load(inputStream);
220             inputStream.close();
221         } catch (Exception e1) {
222             throw new NoPropertiesFile();
223         }
224 
225         try {
226             LOGGER.debug("Lade Server Antworten Datei.");
227             serverAnswers = ResourceBundle.getBundle("server");
228         } catch (Exception e2) {
229             throw new NoServerAnswerFile();
230         }
231 
232         try {
233             LOGGER.debug("Lade Log-Nachrichten Datei.");
234             logMessages = ResourceBundle.getBundle("logging");
235         } catch (Exception e3) {
236             throw new NoLogMessagesFile();
237         }
238 
239     }// Ende JCyrAdm(String properties)
240 
241     /**
242      * Methode um eine Verbindung zum Server aufzubauen, es muss der Parameter
243      * "ssl" gesetzt werden. Wenn TRUE übergeben wird dann wird eine
244      * SSL-Verbindung zum angebenen Port aufgebaut.
245      *
246      * @param ssl - Boolean mit dem zwischen SSL und Plain umgeschaltet wird.
247      * @throws IOException - Unbekannter Host oder Unmöglich den Stream zu
248      *             öffnen
249      */
250     public final void connect(final Boolean ssl) throws IOException {
251         LOGGER.debug(logMessages.getString("logger.trace.connect"));
252         if (ssl) {
253         	LOGGER.trace("öffne Verschlüsselte Verbindung");
254             if (isNull(port)) {
255                 port = DEFAULT_IMAP_SSL_PORT;
256             }
257             SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory
258                     .getDefault();
259             sslRequestSocket = (SSLSocket) factory.createSocket(host, port);
260             out = new PrintStream(sslRequestSocket.getOutputStream());
261             out.flush();
262             in = new BufferedReader(new InputStreamReader(
263                     sslRequestSocket.getInputStream()));
264         } else {
265         	LOGGER.trace("öffne Ungesicherte Verbindung");
266             if (isNull(port)) {
267                 port = DEFAULT_IMAP_PORT;
268             }
269             requestSocket = new Socket(host, port);
270             out = new PrintStream(requestSocket.getOutputStream());
271             out.flush();
272             in = new BufferedReader(new InputStreamReader(
273                     requestSocket.getInputStream()));
274 
275         }
276         welcomeMsg = in.readLine();
277         LOGGER.debug("Server >| " + welcomeMsg);
278     } // Ende connect()
279 
280     /**
281 	 * Methode um die Verbindung zum Server zu trennen.
282 	 * 
283 	 * @throws IOException - wenn der Stream schon geschlossen ist oder
284 	 *             Verbindung abgelaufen ist.
285 	 */
286     public final void disconnect() throws IOException {
287         LOGGER.trace(logMessages.getString("logger.trace.disconnect"));
288         if (sslRequestSocket != null) {
289         	LOGGER.trace("schließe Verschlüsselte Verbindung");
290             sslRequestSocket.close();
291         } else {
292         	LOGGER.trace("schließe Ungesicherte Verbindung");
293             requestSocket.close();
294         }
295     } // disconnect()
296 
297     /**
298      * Unfertige Methode !!!! Diese Methode muss dringent überarbeitet werden.
299      * Holt die Capability und setzt die Default-ACLs. .
300      *
301      * @throws IOException - InputStream/OutputStream geschlossen oder nicht
302      *             vorhanden
303      */
304     public final void capability() throws IOException {
305         LOGGER.trace("capability() aufgerufen.");
306         sendCommand(". capability");
307         String line = in.readLine();
308         LOGGER.debug("Server >| " + line);
309         //System.out.println("Server >| " + line);
310         line = in.readLine();
311         LOGGER.debug("Server >| " + line);
312         //System.out.println("Server >| " + line);
313 
314         // // TODO Hier mus noch die Acl Abfrage hin ist jetzt von Hand gesetzt
315         allacl = "lrswipkxtecda";
316     }
317 
318     /**
319      * Mit dieser Methode wird der Administrationsbenutzer am Server
320      * angemeldet.
321      *
322      * @throws NoServerResponse - Keine Antwort vom Server erhalten.
323      * @throws UnexpectedServerAnswer - Unerwartete Antwort vom Server.
324      * @throws AuthenticationFailure 
325      */
326     public final void login() throws NoServerResponse, UnexpectedServerAnswer, AuthenticationFailure {
327         LOGGER.trace("login() aufgerufen.");
328         sendCommand(". login \"" + administrator + "\" \"" + password + "\"");
329         try {
330             // Lese Antwort vom Server
331             String line = in.readLine();
332             LOGGER.debug("Server >| " + line);
333 
334             // Wenn User oder Passwort falsch
335             if(serverAnswers.getString("server.answer.login.failed")
336                     .contentEquals(new StringBuffer(line))) {
337                 LOGGER.error("Fehler >| " + line);
338                 throw new AuthenticationFailure();
339             }
340             // Wenn Benutzer erfolgreich angemeldet wurde
341             else if(Pattern.matches(serverAnswers.getString("server.answer.login"), line)) {
342                 LOGGER.info("Authen >| " + line);
343             }
344             // In allen anderen Fällen
345             else {
346                 System.out.println(serverAnswers.getString("server.answer.login"));
347                 LOGGER.error("Fehler >| " + line);
348                 throw new UnexpectedServerAnswer();
349             }
350 
351         } catch (IOException e) {
352             throw new NoServerResponse();
353         }
354     }// Ende login()
355 
356     /**
357      * Mit dieser Methode meldet man sich vom Server ab, es werden auch alle
358      * Streams geschlossen.
359      *
360      * @throws NoServerResponse - Keine Antwort vom Server.
361      * @throws NoServerStream - Kein Stream vom Server vorhanden.
362      * @throws UnexpectedServerAnswer - Unerwartete Server Antwort erhalten.
363      */
364     public final void logout() throws NoServerResponse, NoServerStream, UnexpectedServerAnswer {
365         LOGGER.trace("logout() aufgerufen.");
366 
367         // Sende Logout Nachricht
368         sendCommand(". logout");
369 
370         try {
371             // Werte erste Server Antwort aus
372             String line = in.readLine();
373             LOGGER.debug("Server >| " + line);
374             if(!serverAnswers.getString("server.answer.logout")
375                     .contentEquals(new StringBuffer(line))) {
376                 LOGGER.error("Fehler >| " + line);
377                 throw new UnexpectedServerAnswer();
378             }
379         } catch (IOException e) {
380             LOGGER.error("Fehler >| Keine Antwort von Server erhalten");
381             throw new NoServerResponse();
382         }
383 
384         try {
385             // Werte zweite Server Antwort aus
386             String line = in.readLine();
387             LOGGER.debug("Server >| " + line);
388             if(!serverAnswers.getString("server.answer.ok")
389                     .contentEquals(new StringBuffer(line))) {
390                 LOGGER.error("Fehler >| " + line);
391                 throw new UnexpectedServerAnswer();
392             }
393         } catch (IOException e) {
394             LOGGER.error("Fehler >| Keine Antwort von Server erhalten");
395             throw new NoServerResponse();
396         }
397 
398         try {
399             // Schließe InputStream
400             in.close();
401         } catch (IOException e) {
402             LOGGER.error("Fehler >| Keine Stream vom Server vorhanden");
403             throw new NoServerStream();
404         }
405         // Schließe OutputStream
406         out.close();
407     }// Ende logout()
408 
409     /**
410      * Mit dieser Methode können die ACLs einer bestimmten Mailbox abgefragt
411      * werden.
412      *
413      * @param mailbox - Die Mailbox für die die ACLs abgefragt werden sollen
414      * @throws NoValidMailboxName - // TODO Dokumentation
415      * @throws NoServerResponse 
416      * @throws UnexpectedServerAnswer 
417      */
418     public final void acl(final String mailbox) throws NoValidMailboxName,
419             NoServerResponse, UnexpectedServerAnswer {
420         /*
421          * Prüfen ob der übergebene Mailboxname gültig ist.
422          */
423         if (!isValid(mailbox)) {
424             LOGGER.error("Fehler >| Ungültiger Mailboxname");
425             throw new NoValidMailboxName();
426         }
427 
428         /*
429          * Kommando absetzen.
430          */
431         sendCommand(". getacl \"user." + mailbox + "\"");
432 
433         /*
434          * Erste Antwortzeile einlesen.
435          */
436         try {
437             String line = in.readLine();
438             LOGGER.debug("Server >| " + line);
439 
440             if(!Pattern.matches(serverAnswers.getString("server.answer.acl"), line)) {
441                 LOGGER.error("Fehler >| " + line);
442                 throw new UnexpectedServerAnswer();
443             }
444 
445             acls = new HashMap<String, String>();
446             String keys[] = line.split(" ");
447             for(int i=0; i < keys.length; i++) {
448                 if(i > 2) {
449                     if(i % 2 == 1) {
450                         acls.put(keys[i], keys[i+1]);
451                     }
452                 }
453             }
454 
455         } catch (IOException e) {
456             LOGGER.error("Fehler >| Keine Antwort von Server erhalten");
457             throw new NoServerResponse();
458         }
459 
460         /*
461          * Zweite Antwortzeile einlesen.
462          */
463         try {
464             String line = in.readLine();
465             LOGGER.debug("Server >| " + line);
466             if(!serverAnswers.getString("server.answer.ok")
467                     .contentEquals(new StringBuffer(line))) {
468                 LOGGER.error("Fehler >| " + line);
469                 throw new UnexpectedServerAnswer();
470             }
471         } catch (IOException e) {
472             LOGGER.error("Fehler >| Keine Antwort von Server erhalten");
473             throw new NoServerResponse();
474         }
475     }// Ende acl(String)
476 
477     /**
478      * Mit dieser Methode können für eine bestimmte Mailbox, Rechte für einen
479      * bestimmten Benutzer gesetzt werden.
480      *
481      * @param mailbox - Die Mailbox für die die Rechte gesetzt werden sollen.
482      * @param user - Benutzer für die die Rechte gelten sollen.
483      * @param acl - Rechte die für den Benutzer gelten sollen.
484      * @throws NoValidMailboxName -
485      * @throws NoServerResponse 
486      * @throws UnexpectedServerAnswer 
487      */
488     public final void setAcl(final String mailbox, final String user,
489             final String acl) throws NoValidMailboxName, NoServerResponse, UnexpectedServerAnswer {
490         /*
491          * Prüfen ob der übergebene Mailboxname gültig ist.
492          */
493         if (!isValid(mailbox)) {
494             LOGGER.error("Fehler >| Ungültiger Mailboxname");
495             throw new NoValidMailboxName();
496         }
497 
498         /*
499          * Kommando absetzen.
500          */
501         sendCommand(". setacl \"user." + mailbox + "\" \"" + user + "\" " + acl);
502 
503         /*
504          * Einlesen der Antwortzeile.
505          */
506         try {
507             String line = in.readLine();
508             LOGGER.debug("Server >| " + line);
509             if(!serverAnswers.getString("server.answer.ok")
510                     .contentEquals(new StringBuffer(line))) {
511                 LOGGER.error("Fehler >| " + line);
512                 throw new UnexpectedServerAnswer();
513             }
514         } catch (IOException e) {
515             LOGGER.error("Fehler >| Keine Antwort von Server erhalten");
516             throw new NoServerResponse();
517         }
518     }// Ende setAcl(String, String, String)
519 
520 
521     /**
522      * Mit dieser Methode können die Rechte einer Mailbox die für einen
523      * bestimmten Benutzer existieren gelöscht werden.
524      *
525      * @param mailbox - Mailbox für die die Rechte gelöscht werden sollen.
526      * @param user - Benutzer für den die Rechte gelöscht werden sollen.
527      * @throws NoValidMailboxName - // TODO Dokumentation.
528      * @throws NoServerResponse 
529      * @throws UnexpectedServerAnswer 
530      */
531     public final void deleteAcl(final String mailbox, final String user)
532             throws NoValidMailboxName, NoServerResponse, UnexpectedServerAnswer {
533         /*
534          * Prüfen ob der übergebene Mailboxname gültig ist.
535          */
536         if (!isValid(mailbox)) {
537             LOGGER.error("Fehler >| Ungültiger Mailboxname");
538             throw new NoValidMailboxName();
539         }
540 
541         /*
542          * Kommando absetzen.
543          */
544         sendCommand(". deleteacl \"user." + mailbox + "\" \"" + user + "\"");
545 
546         /*
547          * Antwortzeile auswerten.
548          */
549         try {
550             String line = in.readLine();
551             LOGGER.debug("Server >| " + line);
552             if(!serverAnswers.getString("server.answer.ok")
553                     .contentEquals(new StringBuffer(line))) {
554                 LOGGER.error("Fehler >| " + line);
555                 throw new UnexpectedServerAnswer();
556             }
557         } catch (IOException e) {
558             LOGGER.error("Fehler >| Keine Antwort von Server erhalten");
559             throw new NoServerResponse();
560         }
561 
562     }// Ende deleteAcl(String, String)
563 
564     /**
565      * Methode zum berechnen der Quota der aktuellen Mailbox, die Werte können
566      * über die entsprechenden Methoden abgerufen werden.
567      *
568      * @param mailbox - Mailbox für die die Quota berechnet werden soll.
569      * @throws IOException - InputStream/OutputStream geschlossen oder nicht
570      *             vorhanden
571      * @throws NoMailbox - TODO doku
572      * @throws NoQuota - TODO doku
573      * @throws UnexpectedExtraArguments - TODO doku
574      * @throws NoServerResponse - TODO doku
575      * @throws NoValidMailboxName - TODO doku
576      */
577     public final void quota(final String mailbox) throws IOException,
578             NoMailbox, NoQuota, UnexpectedExtraArguments, NoServerResponse,
579             NoValidMailboxName {
580 
581         /*
582          * Prüfen ob der übergebene Mailboxname gültig ist.
583          */
584         if (!isValid(mailbox)) {
585             LOGGER.error("Fehler >| Ungültiger Mailboxname");
586             throw new NoValidMailboxName();
587         }
588 
589         /*
590          * Absenden des Befehls und auslesen der ersten Ergebniszeile.
591          */
592         sendCommand(". getquota \"user." + mailbox + "\"");
593         String line = in.readLine();
594         LOGGER.debug("Server >| " + line);
595 
596         /*
597          * Prüfen ob der Server eine Antwort geschickt hat.
598          */
599         if (isNull(line)) {
600             LOGGER.warn("Kein Antwort vom Server.");
601             throw new NoServerResponse();
602         }
603 
604         /*
605          * Wird geworfen wenn es die Mailbox nicht gibt.
606          */
607         if (line.startsWith(". NO Mailbox")) {
608             LOGGER.warn("Mailbox existiert nicht.");
609             throw new NoMailbox();
610         }
611 
612         /*
613          * Wird geworfen wenn keine Quota gesetzt worden ist .
614          */
615         if (line.startsWith(". NO Quota root does not exist")) {
616             LOGGER.warn("Es wurde bis jetzt noch keine Quota gesetzt.");
617             throw new NoQuota();
618         }
619 
620         /*
621          * Wird geworfen wenn der Methode unbekannte Parameter oder Zeichen
622          * übergeben wurden.
623          */
624         if (line.startsWith(". BAD Unexpected extra arguments to Getquota")) {
625             LOGGER.warn("Es wurden weiter Argumente dem Befehl hinzugefügt.");
626             throw new UnexpectedExtraArguments();
627         }
628 
629         /*
630          * Wenn keine Quota exsistiert bzw. die Antwort nicht "* QUOTA enthält
631          * dann wird eine Exception geworfen.
632          */
633         if (!line.startsWith("* QUOTA")) {
634             LOGGER.warn("In der Server-Anwort war keine Quota enthalten.");
635             // TODO Exception hier hin.
636         }
637 
638         /*
639          * Setzen der Index Elemente.
640          */
641         int start = line.lastIndexOf("(");
642         int end = line.lastIndexOf(")");
643 
644         /*
645          * Zerlegen des Ergebnisses und schreiben der Quota und des
646          * Benutzten Platzes in die Variablen.
647          */
648         String[] storage = line.substring(start + 1, end).split(" ");
649         used = new BigDecimal(storage[1]);
650         quota = new BigDecimal(storage[2]);
651         LOGGER.debug(line.substring(start + 1, end));
652 
653 
654         /*
655          * Errechnen der Load und befüllung der entsprechenden Variable.
656          */
657         load = used.multiply(new BigDecimal("100")).divide(quota, 2,
658                 BigDecimal.ROUND_UP);
659 
660         /*
661          * Auslesen der zweiten Antwortzeile
662          */
663         line = in.readLine();
664         LOGGER.debug("Server >| " + line);
665 
666         /*
667          * Prüfen ob der Server eine Antwort geschickt hat.
668          */
669         if (isNull(line)) {
670             LOGGER.warn("Kein Antwort vom Server.");
671             throw new NoServerResponse();
672         }
673 
674         /*
675          * Exceptions je nach Antwortzeile.
676          */
677         if (!line.startsWith(". OK")) {
678             LOGGER.warn(
679                     "Der letzte Befehl wurde nicht erfolgreich ausgeführt."
680                     );
681             // TODO hier mus noch eine Exception hin
682         }
683 
684     }// Ende quota(String mailbox)
685 
686     /**
687      * Methode zum setzten der Quota einer Mailbox.
688      *
689      * @param mailbox - Hier. // TODO Doku hier
690      * @param quotaToSet - Hier. // TODO Doku hier
691      * @throws IOException - TODO doku
692      * @throws NoValidMailboxName -
693      */
694     public final void setQuota(final String mailbox,
695             final BigDecimal quotaToSet)
696             throws IOException, NoValidMailboxName {
697         /*
698          * Prüfen ob der übergebene Mailboxname gültig ist.
699          */
700         if (!isValid(mailbox)) {
701             LOGGER.warn("Ungültiger Mailboxname");
702             throw new NoValidMailboxName();
703         }
704 
705         /*
706          * Sende Kommando.
707          */
708         sendCommand((new StringBuilder())
709                 .append(". setquota \"")
710                 .append("user.")
711                 .append(mailbox)
712                 .append("\" (STORAGE ")
713                 .append(quotaToSet)
714                 .append(")").toString());
715 
716         String line = in.readLine();
717         LOGGER.debug("Server >| " + line);
718         //System.out.println("Server >| " + line);
719 
720         // ". setquota \"$mb_name\" (STORAGE $quota)"
721         // // TODO hier mus code hin
722     }// Ende setQuota()
723 
724     /**
725      * Methode zum erstellen einer Mailbox mit dem Namen "mailbox".
726      *
727      * @param mailbox - String mit dem Namen der Mailbox (i.e.
728      *            "mailboxname" ohne [user.])
729      * @throws IOException - InputStream/OutputStream geschlossen oder nicht
730      *             vorhanden
731      * @throws MailboxExists - Die Mailbox die erstellt werden soll exsistiert
732      *             bereits.
733      * @throws NoServerResponse - //TODO Dokumentation
734      * @throws NoValidMailboxName - //TODO Dokumentation
735      */
736     public final void createMailBox(final String mailbox) throws IOException,
737             MailboxExists, NoServerResponse, NoValidMailboxName {
738         /*
739          * Prüfen ob der übergebene Mailboxname gültig ist.
740          */
741         System.out.println(mailbox);
742         if (!isValid(mailbox)) {
743 
744             LOGGER.warn("Ungültiger Mailboxname");
745             throw new NoValidMailboxName();
746         }
747 
748         /*
749          * Kommando absetzen.
750          */
751         sendCommand((new StringBuilder())
752                 .append(". create \"")
753                 .append("user.")
754                 .append(mailbox)
755                 .append("\"")
756                 .toString());
757 
758         /*
759          * Antwortzeile auslesen.
760          */
761         String line = in.readLine();
762         LOGGER.debug("Server >| " + line);
763 
764         /*
765          * Prüfen ob es eine Serverantwort gibt.
766          */
767         if (isNull(line)) {
768             LOGGER.warn("Keine Antwort vom Server.");
769             throw new NoServerResponse();
770         }
771 
772         /*
773          * Wirft Exception wenn es die Mailbox bereits gibt.
774          */
775         if (line.startsWith(". NO Mailbox already exists")) {
776             LOGGER.warn("Die Mailbox existiert schon.");
777             throw new MailboxExists();
778         }
779     }// Ende createMailBox()
780 
781     /**
782      * Hier. // TODO Doku hier
783      *
784      * @param mailbox - Hier. // TODO Doku hier
785      * @throws IOException - InputStream/OutputStream geschlossen oder nicht
786      *             vorhanden
787      * @throws NoValidMailboxName -
788      */
789     public final void deleteMailBox(final String mailbox) throws IOException,
790             NoValidMailboxName {
791         /*
792          * Prüfen ob der übergebene Mailboxname gültig ist.
793          */
794         if (!isValid(mailbox)) {
795             LOGGER.warn("Ungültiger Mailboxname");
796             throw new NoValidMailboxName();
797         }
798 
799         /*
800          * Setzen der Rechte für den Administrationsbenutzer
801          */
802         try {
803             setAcl(mailbox, administrator, allacl);
804         } catch (NoServerResponse e) {
805             // TODO Auto-generated catch block
806             e.printStackTrace();
807         } catch (UnexpectedServerAnswer e) {
808             // TODO Auto-generated catch block
809             e.printStackTrace();
810         }
811 
812         sendCommand(". delete \"user." + mailbox + "\"");
813         String line = in.readLine();
814         LOGGER.debug("Server >| " + line);
815         //System.out.println("Server >| " + line);
816     }// Ende deleteMailBox()
817 
818     /**
819      * Methode zum setzen des Hostnamen oder der IP-Adresse des Servers mit dem
820      * eine Verbindung aufgebaut werden soll. Falls der Host nicht gesetzt ist
821      * wird localhost als hostname benutzt.
822      *
823      * @param hostname - Der Name oder die IP-Adresse des Servers zu dem eine
824      *            Verbindung aufgebaut werden soll.
825      */
826     public final void setHost(final String hostname) {
827         this.host = hostname;
828     }// Ende setHost()
829 
830     /**
831      * Methode um die Port-Nummer des Server zu verändern, normalerweise nicht
832      * nötig, wenn der Server auf den Standard-Ports betrieben wird.
833      *
834      * @param portNumber - Port-Nummer die für die Verbindung zum Server
835      *            benutzt werden soll.
836      */
837     public final void setPort(final Integer portNumber) {
838         this.port = portNumber;
839     }// Ende setPort()
840 
841     /**
842      * Hier. // TODO Doku hier
843      *
844      * @param set - Hier. // TODO Doku hier
845      */
846     public final void setAdministrator(final String set) {
847         this.administrator = set;
848     }// Ende setAdministrator()
849 
850     /**
851      * Hier. // TODO Doku hier
852      *
853      * @param set - Hier. // TODO Doku hier
854      */
855     public final void setPassword(final String set) {
856         this.password = set;
857     }// Ende setPasswort()
858 
859     /**
860      * Liefert die Version des Server mit dem gerade eine Verbindung aufgebaut
861      * ist.
862      *
863      * @return String - Cyrus Version
864      * @throws IOException - InputStream/OutputStream geschlossen oder nicht
865      *             vorhanden
866      */
867     public final String version() throws IOException {
868     	sendCommand(". id NIL");
869         String line = in.readLine();
870         LOGGER.debug("Server >| " + line);
871 
872         if (isNull(line)) {
873             // TODO Hier kommt noch Exception
874             LOGGER.warn("Keine Server Antwort.");
875         }
876 
877         int start = line.indexOf("(");
878         int end = line.lastIndexOf(")");
879 
880         String[] storage = line.substring(start + 1, end).split("\" \"");
881 
882         for (int i = 0; i < storage.length; i++) {
883             idMap.put(storage[i], storage[i + 1]);
884             i++;
885         }
886 
887         line = in.readLine();
888         LOGGER.debug("Server >| " + line);
889         //System.out.println("Server >| " + line);
890 
891         return idMap.get("version").split(" ")[0];
892     }// Ende version()
893 
894     /**
895      * Mit Hilfe dieser Methode kann man sich die Wilkommensnachricht des Server
896      * abfragen, die nach dem aufruf der Methode connect(Boolean ssl) empfangen
897      * wurde.
898      *
899      * @return String - Willkommensnachricht des Servers.
900      */
901     public final String getWelcomeMsg() {
902         return welcomeMsg;
903     }// Ende getWelcomeMsg()
904 
905     /**
906      * TODO Doku
907      * @return
908      */
909     public Map<String, String> getAcls() {
910         return acls;
911     }// Ende getAcls;
912 
913     /**
914      * Bevor die Methode getUsed() aufgerufen werden kann, muss die Methode
915      * quota(String mailbox) aufgrufen werden. Die Methode getUsed() liefert
916      * dann den benutzen Teil der Quota der Mailbox.
917      *
918      * @return BigDecimal - Benutzer Teil der Quota der Mailbox die mit der
919      *         Methode quota(String mailbox) übergeben wurde.
920      * @throws QuotaNotInitialized - TODO doku
921      */
922     public final BigDecimal getUsed() throws QuotaNotInitialized {
923         if (isNull(used)) {
924             throw new QuotaNotInitialized();
925         }
926         return used;
927     }// Ende getUsed()
928 
929     /**
930      * Bevor die Methode getQuota() aufgerufen werden kann, muss die Methode
931      * quota(String mailbox) aufgrufen werden. Die Methode getQuota() liefert
932      * dann die aktuelle Quota der Mailbox.
933      *
934      * @return BigDecimal - Quota der Mailbox die mit der Methode quota(String
935      *         mailbox) übergeben wurde.
936      * @throws QuotaNotInitialized - TODO doku
937      */
938     public final BigDecimal getQuota() throws QuotaNotInitialized {
939         if (isNull(used)) {
940             throw new QuotaNotInitialized();
941         }
942         return quota;
943     }// Ende getQuota()
944 
945     /**
946      * Bevor die Methode getLoad() aufgerufen werden kann, muss die Methode
947      * quota(String mailbox) aufgrufen werden. Die Methode getLoad() liefert
948      * dann die aktuelle Load der Mailbox.
949      *
950      * @return BigDecimal - Load der Mailbox die mit der Methode quota(String
951      *         mailbox) übergeben wurde.
952      * @throws QuotaNotInitialized - TODO doku
953      */
954     public final BigDecimal getLoad() throws QuotaNotInitialized {
955         if (isNull(used)) {
956             throw new QuotaNotInitialized();
957         }
958         return load;
959     }// Ende getLoad()
960 
961     /**
962 	 * Hilfs-Methode um ein Kommando an den Server zu senden.
963 	 * 
964 	 * @param command - Kommando das an den Server gesendet werden soll.
965 	 */
966     private void sendCommand(final String command) {
967         out.println(command);
968         out.flush();
969         LOGGER.debug("Client >| " + command);
970     }// Ende sendCommand()
971     
972     /**
973      * Hilfs-Methode die prüft ob ein Object Null ist.
974      *
975      * @param isNull - Objekt das getestet werden soll.
976      * @return Boolean - Wahrheitswert: True wenn das Objekt Null ist.
977      */
978     private Boolean isNull(final Object isNull) {
979     	return isNull != null ? false : true;
980     }// Ende isNull()
981 
982     /**
983      * Hilfs-Methode die testet ob ein String ein gültiger String im Sinne
984      * einer Cyrus Mailbox ist.
985      *
986      * @param mbString - String der als Mailbox übergeben wurde.
987      * @return Boolean - Wenn gültig dann True.
988      */
989     private Boolean isValid(final String mbString) {
990         return Pattern.matches("[a-zA-Z_]*", mbString)? true : false;
991     }
992 
993     /**
994 	 * Hilfs-Methode die dazu dient den String einer zu einem bestimmtem
995 	 * Schlüssel aus der Eigenschaftsdatei zu holen.
996 	 * 
997 	 * @param text - Schlüssel unter dem der String abgelegt ist.
998 	 * @return String - Der enthaltente String zum angegebenen Schlüssel oder
999 	 *         wenn der Schlüssel nicht gefunden wurde der übergebene String.
1000 	 */
1001     @Deprecated
1002     private String getText(String text) {
1003         if ((props != null) && (props.getProperty(text) != null)) {
1004             return props.getProperty(text);
1005         }
1006         return text;
1007     }// Ende getText()
1008 
1009     
1010 }// Ende class