View Javadoc
1   /*
2    * DavMail POP/IMAP/SMTP/CalDav/LDAP Exchange Gateway
3    * Copyright (C) 2010  Mickael Guessant
4    *
5    * This program is free software; you can redistribute it and/or
6    * modify it under the terms of the GNU General Public License
7    * as published by the Free Software Foundation; either version 2
8    * of the License, or (at your option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with this program; if not, write to the Free Software
17   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18   */
19  package davmail.exchange.dav;
20  
21  import org.apache.log4j.Logger;
22  
23  import java.io.ByteArrayOutputStream;
24  import java.io.IOException;
25  import java.io.OutputStreamWriter;
26  import java.nio.charset.StandardCharsets;
27  import java.util.HashMap;
28  import java.util.HashSet;
29  import java.util.Map;
30  import java.util.Set;
31  
32  /**
33   * Custom Exchange PROPPATCH method.
34   * Supports extended property update with type.
35   */
36  public class ExchangePropPatchMethod extends ExchangeDavMethod {
37      protected static final Logger LOGGER = Logger.getLogger(ExchangePropPatchMethod.class);
38      static final String TYPE_NAMESPACE = "urn:schemas-microsoft-com:datatypes";
39      final Set<PropertyValue> propertyValues;
40  
41      /**
42       * Create PROPPATCH method.
43       *
44       * @param path           path
45       * @param propertyValues property values
46       */
47      public ExchangePropPatchMethod(String path, Set<PropertyValue> propertyValues) {
48          super(path);
49          this.propertyValues = propertyValues;
50      }
51  
52      @Override
53      protected byte[] generateRequestContent() {
54          try {
55              // build namespace map
56              int currentChar = 'e';
57              final Map<String, Integer> nameSpaceMap = new HashMap<>();
58              final Set<PropertyValue> setPropertyValues = new HashSet<>();
59              final Set<PropertyValue> deletePropertyValues = new HashSet<>();
60              for (PropertyValue propertyValue : propertyValues) {
61                  // data type namespace
62                  if (!nameSpaceMap.containsKey(TYPE_NAMESPACE) && propertyValue.getTypeString() != null) {
63                      nameSpaceMap.put(TYPE_NAMESPACE, currentChar++);
64                  }
65                  // property namespace
66                  String namespaceUri = propertyValue.getNamespaceUri();
67                  if (!nameSpaceMap.containsKey(namespaceUri)) {
68                      nameSpaceMap.put(namespaceUri, currentChar++);
69                  }
70                  if (propertyValue.getXmlEncodedValue() == null) {
71                      deletePropertyValues.add(propertyValue);
72                  } else {
73                      setPropertyValues.add(propertyValue);
74                  }
75              }
76              ByteArrayOutputStream baos = new ByteArrayOutputStream();
77              OutputStreamWriter writer = new OutputStreamWriter(baos, StandardCharsets.UTF_8);
78              writer.write("<D:propertyupdate xmlns:D=\"DAV:\"");
79              for (Map.Entry<String, Integer> mapEntry : nameSpaceMap.entrySet()) {
80                  writer.write(" xmlns:");
81                  writer.write((char) mapEntry.getValue().intValue());
82                  writer.write("=\"");
83                  writer.write(mapEntry.getKey());
84                  writer.write("\"");
85              }
86              writer.write(">");
87              if (!setPropertyValues.isEmpty()) {
88                  writer.write("<D:set><D:prop>");
89                  for (PropertyValue propertyValue : setPropertyValues) {
90                      String typeString = propertyValue.getTypeString();
91                      char nameSpaceChar = (char) nameSpaceMap.get(propertyValue.getNamespaceUri()).intValue();
92                      writer.write('<');
93                      writer.write(nameSpaceChar);
94                      writer.write(':');
95                      writer.write(propertyValue.getName());
96                      if (typeString != null) {
97                          writer.write(' ');
98                          writer.write(nameSpaceMap.get(TYPE_NAMESPACE));
99                          writer.write(":dt=\"");
100                         writer.write(typeString);
101                         writer.write("\"");
102                     }
103                     writer.write('>');
104                     writer.write(propertyValue.getXmlEncodedValue());
105                     writer.write("</");
106                     writer.write(nameSpaceChar);
107                     writer.write(':');
108                     writer.write(propertyValue.getName());
109                     writer.write('>');
110                 }
111                 writer.write("</D:prop></D:set>");
112             }
113             if (!deletePropertyValues.isEmpty()) {
114                 writer.write("<D:remove><D:prop>");
115                 for (PropertyValue propertyValue : deletePropertyValues) {
116                     char nameSpaceChar = (char) nameSpaceMap.get(propertyValue.getNamespaceUri()).intValue();
117                     writer.write('<');
118                     writer.write(nameSpaceChar);
119                     writer.write(':');
120                     writer.write(propertyValue.getName());
121                     writer.write("/>");
122                 }
123                 writer.write("</D:prop></D:remove>");
124             }
125             writer.write("</D:propertyupdate>");
126             writer.close();
127             return baos.toByteArray();
128         } catch (IOException e) {
129             throw new RuntimeException(e);
130         }
131     }
132 
133     @Override
134     public String getName() {
135         return "PROPPATCH";
136     }
137 
138 }