Source for gnu.inet.imap.Namespaces

   1: /*
   2:  * Namespaces.java
   3:  * Copyright (C) 2004 The Free Software Foundation
   4:  * 
   5:  * This file is part of GNU inetlib, a library.
   6:  * 
   7:  * GNU inetlib is free software; you can redistribute it and/or modify
   8:  * it under the terms of the GNU General Public License as published by
   9:  * the Free Software Foundation; either version 2 of the License, or
  10:  * (at your option) any later version.
  11:  * 
  12:  * GNU inetlib is distributed in the hope that it will be useful,
  13:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15:  * GNU General Public License for more details.
  16:  * 
  17:  * You should have received a copy of the GNU General Public License
  18:  * along with this library; if not, write to the Free Software
  19:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20:  * 
  21:  * Linking this library statically or dynamically with other modules is
  22:  * making a combined work based on this library.  Thus, the terms and
  23:  * conditions of the GNU General Public License cover the whole
  24:  * combination.
  25:  *
  26:  * As a special exception, the copyright holders of this library give you
  27:  * permission to link this library with independent modules to produce an
  28:  * executable, regardless of the license terms of these independent
  29:  * modules, and to copy and distribute the resulting executable under
  30:  * terms of your choice, provided that you also meet, for each linked
  31:  * independent module, the terms and conditions of the license of that
  32:  * module.  An independent module is a module which is not derived from
  33:  * or based on this library.  If you modify this library, you may extend
  34:  * this exception to your version of the library, but you are not
  35:  * obliged to do so.  If you do not wish to do so, delete this
  36:  * exception statement from your version.
  37:  */
  38: 
  39: package gnu.inet.imap;
  40: 
  41: import java.util.ArrayList;
  42: import java.util.Iterator;
  43: import java.util.List;
  44: import java.util.Map;
  45: import java.util.TreeMap;
  46: 
  47: /**
  48:  * A tuple of IMAP namespaces, as defined in RFC 2342.
  49:  *
  50:  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
  51:  */
  52: public class Namespaces
  53: {
  54: 
  55:   /**
  56:    * An individual namespace specification.
  57:    */
  58:   public static class Namespace
  59:   {
  60: 
  61:     String prefix;
  62:     char delimiter;
  63:     Map extensions;
  64: 
  65:     /**
  66:      * Returns the namespace prefix.
  67:      */
  68:     public String getPrefix()
  69:     {
  70:       return prefix;
  71:     }
  72: 
  73:     /**
  74:      * Returns the delimiter character for the namespace.
  75:      */
  76:     public char getDelimiter()
  77:     {
  78:       return delimiter;
  79:     }
  80: 
  81:     /**
  82:      * Returns the dictionary of extension values for the namespace,
  83:      * or <code>null</code> if there are no extensions.
  84:      */
  85:     public Map getExtensions()
  86:     {
  87:       return extensions;
  88:     }
  89: 
  90:     /**
  91:      * Debugging.
  92:      */
  93:     public String toString()
  94:     {
  95:       StringBuffer buf = new StringBuffer();
  96:       buf.append('(');
  97:       buf.append(quote(prefix));
  98:       buf.append(' ');
  99:       buf.append(quote(delimiter));
 100:       if (extensions != null)
 101:         {
 102:           buf.append(' ');
 103:           for (Iterator i = extensions.entrySet().iterator(); i.hasNext(); )
 104:             {
 105:               Map.Entry entry = (Map.Entry) i.next();
 106:               String key = (String) entry.getKey();
 107:               buf.append(quote(key));
 108:               buf.append(' ');
 109:               buf.append(format(entry.getValue()));
 110:             }
 111:         }
 112:       buf.append(')');
 113:       return buf.toString();
 114:     }
 115: 
 116:     static String quote(String text)
 117:     {
 118:       return '"' + text + '"';
 119:     }
 120: 
 121:     static String quote(char c)
 122:     {
 123:       char[] chars = new char[] { '"', c, '"' };
 124:       return new String(chars);
 125:     }
 126: 
 127:     private String format(Object value)
 128:     {
 129:       if (value == null)
 130:         {
 131:           return IMAPConstants.NIL;
 132:         }
 133:       else if (value instanceof String)
 134:         {
 135:           return quote((String) value);
 136:         }
 137:       else
 138:         {
 139:           List list = (List) value;
 140:           int len = list.size();
 141:           StringBuffer buf = new StringBuffer();
 142:           buf.append('(');
 143:           for (int i = 0; i < len; i++)
 144:             {
 145:               if (i > 0)
 146:                 {
 147:                   buf.append(' ');
 148:                 }
 149:               buf.append(format(list.get(i)));
 150:             }
 151:           buf.append(')');
 152:           return buf.toString();
 153:         }
 154:     }
 155:     
 156:   }
 157: 
 158:   List personal;
 159:   List other;
 160:   List shared;
 161: 
 162:   Namespaces(String text)
 163:   {
 164:     List acc = new ArrayList();
 165:     int len = text.length();
 166:     parse(text, 0, len, acc);
 167: 
 168:     len = acc.size();
 169:     if (len > 0)
 170:       {
 171:         personal = parseNamespaceList(acc.get(0));
 172:         if (len > 1)
 173:           {
 174:             other = parseNamespaceList(acc.get(1));
 175:             if (len > 2)
 176:               {
 177:                 shared = parseNamespaceList(acc.get(2));
 178:               }
 179:           }
 180:       }
 181:   }
 182: 
 183:   /**
 184:    * Returns the list of personal namespaces.
 185:    */
 186:   public Namespace[] getPersonal()
 187:   {
 188:     return toArray(personal);
 189:   }
 190: 
 191:   /**
 192:    * Returns the list of other users' namespaces.
 193:    */
 194:   public Namespace[] getOther()
 195:   {
 196:     return toArray(other);
 197:   }
 198: 
 199:   /**
 200:    * Returns the list of shared namespaces.
 201:    */
 202:   public Namespace[] getShared()
 203:   {
 204:     return toArray(shared);
 205:   }
 206: 
 207:   private Namespace[] toArray(List namespaceList)
 208:   {
 209:     if (namespaceList == null)
 210:       {
 211:         return null;
 212:       }
 213:     Namespace[] ret = new Namespace[namespaceList.size()];
 214:     namespaceList.toArray(ret);
 215:     return ret;
 216:   }
 217: 
 218:   /**
 219:    * Parse the specified text into an S-expression.
 220:    */
 221:   static int parse(String text, int start, int len, List acc)
 222:   {
 223:     StringBuffer buf = new StringBuffer();
 224:     boolean inLiteral = false;
 225:     for (int i = start; i < len; i++)
 226:       {
 227:         char c = text.charAt(i);
 228:         if (inLiteral)
 229:           {
 230:             if (c == '"')
 231:               {
 232:                 String literal = buf.toString();
 233:                 buf.setLength(0);
 234:                 inLiteral = false;
 235:                 acc.add(literal);
 236:               }
 237:             else
 238:               {
 239:                 buf.append(c);
 240:               }
 241:           }
 242:         else
 243:           {
 244:             switch (c)
 245:               {
 246:               case ' ':
 247:                 String token = buf.toString();
 248:                 if (IMAPConstants.NIL.equals(token))
 249:                   {
 250:                     acc.add(null);
 251:                   }
 252:                 buf.setLength(0);
 253:                 break;
 254:               case '"':
 255:                 inLiteral = true;
 256:                 buf.setLength(0);
 257:                 break;
 258:               case '(':
 259:                 List sub = new ArrayList();
 260:                 i = parse(text, i + 1, len, sub);
 261:                 acc.add(sub);
 262:                 break;
 263:               case ')':
 264:                 return i;
 265:               }
 266:           }
 267:       }
 268:     return len;
 269:   }
 270: 
 271:   private List parseNamespaceList(Object ns)
 272:   {
 273:     if (ns == null)
 274:       {
 275:         return null;
 276:       }
 277:     List list = (List) ns;
 278:     int len = list.size();
 279:     List ret = new ArrayList(len);
 280:     for (int i = 0; i < len; i++)
 281:       {
 282:         ret.add(parseNamespace((List) list.get(i)));
 283:       }
 284:     return ret;
 285:   }
 286: 
 287:   private Namespace parseNamespace(List comps)
 288:   {
 289:     int len = comps.size();
 290:     Namespace ns = new Namespace();
 291:     ns.prefix = (String) comps.get(0);
 292:     ns.delimiter = ((String) comps.get(1)).charAt(0);
 293:     if (len > 2)
 294:       {
 295:         ns.extensions = new TreeMap();
 296:         for (int i = 2; i < len; i += 2)
 297:           {
 298:             String key = (String) comps.get(i);
 299:             Object val = (i == len - 1) ? null : comps.get(i + 1);
 300:             ns.extensions.put(key, val);
 301:           }
 302:       }
 303:     return ns;
 304:   }
 305: 
 306:   /**
 307:    * Debugging.
 308:    */
 309:   public String toString()
 310:   {
 311:     StringBuffer buf = new StringBuffer();
 312:     appendNamespaceList(buf, personal);
 313:     buf.append(' ');
 314:     appendNamespaceList(buf, other);
 315:     buf.append(' ');
 316:     appendNamespaceList(buf, shared);
 317:     return buf.toString();
 318:   }
 319: 
 320:   private void appendNamespaceList(StringBuffer buf, List list)
 321:   {
 322:     if (list == null)
 323:       {
 324:         buf.append(IMAPConstants.NIL);
 325:       }
 326:     else
 327:       {
 328:         int len = list.size();
 329:         buf.append('(');
 330:         for (int i = 0; i < len; i++)
 331:           {
 332:             if (i > 0)
 333:               {
 334:                 buf.append(' ');
 335:               }
 336:             buf.append(list.get(i));
 337:           }
 338:         buf.append(')');
 339:       }
 340:   }
 341: 
 342: }