1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package davmail.exchange.graph;
21
22 import davmail.Settings;
23 import davmail.exception.DavMailException;
24 import davmail.exchange.VObject;
25 import davmail.exchange.VProperty;
26 import davmail.util.DateUtil;
27 import davmail.util.StringUtil;
28 import org.apache.log4j.Logger;
29 import org.codehaus.jettison.json.JSONArray;
30 import org.codehaus.jettison.json.JSONException;
31 import org.codehaus.jettison.json.JSONObject;
32
33 import java.text.ParseException;
34 import java.text.SimpleDateFormat;
35 import java.util.Date;
36 import java.util.HashMap;
37 import java.util.HashSet;
38 import java.util.Map;
39 import java.util.TimeZone;
40
41
42
43
44 public class GraphObject {
45 protected static final Logger LOGGER = Logger.getLogger(GraphObject.class);
46
47 protected final JSONObject jsonObject;
48 protected int statusCode;
49
50 public GraphObject() {
51 this.jsonObject = new JSONObject();
52 }
53
54 public GraphObject(JSONObject jsonObject) {
55 this.jsonObject = jsonObject;
56 }
57
58 public String optString(String key) {
59
60 return optString(GraphField.get(key));
61 }
62
63 public String optString(GraphField field) {
64 String key = field.getGraphId();
65 if (key == null) {
66 return null;
67 }
68 String value = null;
69
70 if ("keywords".equals(key) || "categories".equals(key)) {
71 JSONArray categoriesArray = jsonObject.optJSONArray("categories");
72 HashSet<String> keywords = new HashSet<>();
73
74 if (categoriesArray != null) {
75 for (int j = 0; j < categoriesArray.length(); j++) {
76 keywords.add(categoriesArray.optString(j));
77 }
78 value = StringUtil.join(keywords, ",");
79 }
80 } else if ("from".equals(key)) {
81 value = formatEmailAddress(jsonObject.optJSONObject(key));
82 } else if ("@odata.etag".equals(key)) {
83
84 String odataEtag = jsonObject.optString("@odata.etag");
85 if (odataEtag != null && odataEtag.startsWith("W/\"") && odataEtag.endsWith("\"")) {
86 value = odataEtag.substring(3, odataEtag.length() - 1);
87 }
88 } else if (!field.isExtended()) {
89
90 value = jsonObject.optString(key, null);
91 } else {
92 JSONArray singleValueExtendedProperties = jsonObject.optJSONArray("singleValueExtendedProperties");
93 if (singleValueExtendedProperties != null) {
94
95 for (int i = 0; i < singleValueExtendedProperties.length(); i++) {
96 JSONObject singleValueObject = singleValueExtendedProperties.optJSONObject(i);
97 if (singleValueObject != null && key.equals(singleValueObject.optString("id"))) {
98 value = singleValueObject.optString("value");
99 }
100 }
101 }
102 }
103 if (field.isDate()) {
104 try {
105 value = GraphExchangeSession.convertDateFromExchange(value);
106 } catch (DavMailException e) {
107 LOGGER.warn("Invalid date " + value + " on field " + key);
108 }
109 }
110 return value;
111 }
112
113 protected String formatEmailAddress(JSONObject jsonObject) {
114 String value = null;
115 if (jsonObject != null) {
116 JSONObject jsonEmailAddress = jsonObject.optJSONObject("emailAddress");
117 if (jsonEmailAddress != null) {
118 value = jsonEmailAddress.optString("name", "") + " <" + jsonEmailAddress.optString("address", "") + ">";
119 }
120 }
121 return value;
122 }
123
124 public String getCalendarUid() {
125 String iCalUId = optString("calendaruid");
126 if (iCalUId == null && Settings.getBooleanProperty("davmail.caldavUIDFromTransactionId",false)) {
127
128 iCalUId = optString("transactionId");
129 }
130 if (iCalUId == null) {
131
132 iCalUId = optString("iCalUId");
133 }
134 return iCalUId;
135 }
136
137 public JSONArray optJSONArray(String key) {
138 return jsonObject.optJSONArray(key);
139 }
140
141
142
143
144
145
146
147
148 public GraphObject put(String alias, String value) throws JSONException {
149 GraphField field = GraphField.get(alias);
150 String key = field.getGraphId();
151
152 if (field.isExtended()) {
153
154 if (field.isNumber() && value == null) {
155 value = "0";
156 }
157 if (field.isBoolean() && value == null) {
158 value = "false";
159 }
160 getSingleValueExtendedProperties().put(new JSONObject().put("id", key).put("value", value == null ? JSONObject.NULL : value));
161 } else {
162 jsonObject.put(key, value == null ? JSONObject.NULL : value);
163 }
164 return this;
165 }
166
167
168
169
170
171
172
173
174 public GraphObject put(String alias, boolean value) throws JSONException {
175 GraphField field = GraphField.get(alias);
176 String key = field.getGraphId();
177
178 if (field.isExtended()) {
179 getSingleValueExtendedProperties().put(new JSONObject().put("id", key).put("value", value));
180 } else {
181 jsonObject.put(key, value);
182 }
183 return this;
184 }
185
186 public GraphObject put(String key, JSONArray value) throws JSONException {
187 jsonObject.put(key, value);
188 return this;
189 }
190
191 public GraphObject put(String key, JSONObject value) throws JSONException {
192 jsonObject.put(key, value);
193 return this;
194 }
195
196
197
198
199
200
201 public void setCategories(String values) throws JSONException {
202 if (values != null) {
203 setCategories(values.split(","));
204 } else {
205 jsonObject.put("categories", new JSONArray());
206 }
207 }
208
209 public void setCategories(String[] values) throws JSONException {
210
211 JSONArray jsonValues = new JSONArray();
212 for (String singleValue : values) {
213 jsonValues.put(singleValue);
214 }
215 jsonObject.put("categories", jsonValues);
216 }
217
218
219
220
221
222
223
224
225 protected JSONArray getSingleValueExtendedProperties() throws JSONException {
226 JSONArray singleValueExtendedProperties = jsonObject.optJSONArray("singleValueExtendedProperties");
227 if (singleValueExtendedProperties == null) {
228 singleValueExtendedProperties = new JSONArray();
229 jsonObject.put("singleValueExtendedProperties", singleValueExtendedProperties);
230 }
231 return singleValueExtendedProperties;
232 }
233
234
235
236
237
238
239
240
241 public String getString(String key) throws JSONException {
242 String value = optString(key);
243 if (value == null) {
244 throw new JSONException("JSONObject[" + key + "] not found.");
245 }
246 return value;
247 }
248
249
250
251
252
253
254
255 public String optSectionString(String section, String key) {
256 JSONObject sectionObject = jsonObject.optJSONObject(section);
257 if (sectionObject != null) {
258 return sectionObject.optString(key, null);
259 }
260 return null;
261 }
262
263 public boolean getBoolean(String key) throws JSONException {
264 return getBoolean(GraphField.get(key));
265 }
266
267 public boolean optBoolean(String key) {
268 return optBoolean(GraphField.get(key));
269 }
270
271 public boolean getBoolean(GraphField field) throws JSONException {
272 String key = field.getGraphId();
273 if (key == null) {
274 return false;
275 }
276 return jsonObject.getBoolean(key);
277 }
278
279 public boolean optBoolean(GraphField field) {
280 String key = field.getGraphId();
281 if (key == null) {
282 return false;
283 }
284 return jsonObject.optBoolean(key);
285 }
286
287 public JSONObject optJSONObject(String key) {
288 return jsonObject.optJSONObject(key);
289 }
290
291
292
293
294
295
296
297
298
299 public Date optDateTimeTimeZone(String key) throws DavMailException {
300 JSONObject sectionObject = jsonObject.optJSONObject(key);
301 if (sectionObject != null) {
302 String timeZone = sectionObject.optString("timeZone");
303 String dateTime = sectionObject.optString("dateTime");
304 if (timeZone != null && dateTime != null) {
305 try {
306 SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS");
307 parser.setTimeZone(DateUtil.getTimeZone(timeZone));
308 return parser.parse(dateTime);
309 } catch (ParseException e) {
310 throw new DavMailException("EXCEPTION_INVALID_DATE", dateTime);
311 }
312 }
313 }
314 return null;
315 }
316
317
318
319
320
321
322 public VProperty getRecurrenceId() throws DavMailException {
323
324 String originalStartTimeZone = optString("originalStartTimeZone");
325
326 String originalStart = optString("originalStart");
327
328 if (originalStartTimeZone != null && originalStart != null && originalStart.length() >= 19) {
329 String convertedOriginalStart = originalStart;
330
331
332 SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
333 parser.setTimeZone(TimeZone.getTimeZone("UTC"));
334
335 String standardTimeZoneId = DateUtil.getStandardTimeZone(originalStartTimeZone);
336 SimpleDateFormat formatter;
337 if (standardTimeZoneId == null) {
338
339 formatter = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
340 formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
341 } else {
342
343 formatter = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
344 formatter.setTimeZone(DateUtil.getTimeZone(standardTimeZoneId));
345 }
346 try {
347 convertedOriginalStart = formatter.format(parser.parse(originalStart));
348 } catch (ParseException e) {
349 LOGGER.warn("Unable to convert to original timezone: " + originalStart + ", " + originalStartTimeZone);
350 }
351
352
353 VProperty recurrenceId = new VProperty("RECURRENCE-ID", convertedOriginalStart);
354 if (standardTimeZoneId != null) {
355 recurrenceId.setParam("TZID", originalStartTimeZone);
356 }
357 return recurrenceId;
358 } else {
359 throw new DavMailException("LOG_MESSAGE", "Missing original start date and timezone");
360 }
361 }
362
363
364
365 public int optInt(String key) {
366 return jsonObject.optInt(key);
367 }
368
369 public String toString(int indentFactor) throws JSONException {
370 return jsonObject.toString(indentFactor);
371 }
372
373 protected static final Map<String, String> vTodoToTaskStatusMap = new HashMap<>();
374 protected static final Map<String, String> taskTovTodoStatusMap = new HashMap<>();
375
376 static {
377
378
379 taskTovTodoStatusMap.put("inProgress", "IN-PROCESS");
380 taskTovTodoStatusMap.put("completed", "COMPLETED");
381 taskTovTodoStatusMap.put("waitingOnOthers", "NEEDS-ACTION");
382 taskTovTodoStatusMap.put("deferred", "CANCELLED");
383
384
385 vTodoToTaskStatusMap.put("IN-PROCESS", "inProgress");
386 vTodoToTaskStatusMap.put("COMPLETED", "completed");
387 vTodoToTaskStatusMap.put("NEEDS-ACTION", "waitingOnOthers");
388 vTodoToTaskStatusMap.put("CANCELLED", "deferred");
389 }
390
391 public void setTaskStatusFromVTodo(VObject vEvent) throws JSONException {
392 String taskStatus = vTodoToTaskStatusMap.get(vEvent.getPropertyValue("STATUS"));
393 if (taskStatus == null) {
394 taskStatus = "notStarted";
395 }
396 put("status", taskStatus);
397 }
398
399 public String getVTodoStatusFromTask() {
400 return taskTovTodoStatusMap.get(optString("status"));
401 }
402
403 protected static final Map<String, String> importanceToPriorityMap = new HashMap<>();
404
405 static {
406 importanceToPriorityMap.put("high", "1");
407 importanceToPriorityMap.put("normal", "5");
408 importanceToPriorityMap.put("low", "9");
409 }
410
411 protected static final Map<String, String> priorityToImportanceMap = new HashMap<>();
412
413 static {
414
415 priorityToImportanceMap.put("0", "normal");
416
417 priorityToImportanceMap.put("1", "high");
418 priorityToImportanceMap.put("2", "high");
419 priorityToImportanceMap.put("3", "high");
420 priorityToImportanceMap.put("4", "normal");
421 priorityToImportanceMap.put("5", "normal");
422 priorityToImportanceMap.put("6", "normal");
423 priorityToImportanceMap.put("7", "low");
424 priorityToImportanceMap.put("8", "low");
425 priorityToImportanceMap.put("9", "low");
426 }
427
428 protected String getTaskPriority() {
429 String taskImportance = optString("importance");
430 String taskPriority = null;
431 if (taskImportance != null) {
432 taskPriority = importanceToPriorityMap.get(taskImportance);
433 }
434 return taskPriority;
435 }
436
437 public void setTaskImportanceFromVTodo(VObject vEvent) throws JSONException {
438 String taskImportance = priorityToImportanceMap.get(vEvent.getPropertyValue("PRIORITY"));
439 if (taskImportance == null) {
440 taskImportance = "normal";
441 }
442 put("importance", taskImportance);
443 }
444
445 }
446