001/* 002 * Copyright 2017 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.exchange; 017 018import java.net.URI; 019import java.net.URISyntaxException; 020import java.util.ArrayList; 021import java.util.Calendar; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.Date; 025import java.util.GregorianCalendar; 026import java.util.HashMap; 027import java.util.List; 028import java.util.Map; 029import java.util.Set; 030import java.util.TimeZone; 031 032import org.apache.avalon.framework.service.ServiceException; 033import org.apache.avalon.framework.service.ServiceManager; 034import org.apache.commons.lang3.EnumUtils; 035import org.apache.commons.lang3.StringUtils; 036import org.joda.time.DateTime; 037import org.jsoup.Jsoup; 038 039import org.ametys.core.user.CurrentUserProvider; 040import org.ametys.core.user.User; 041import org.ametys.core.user.UserIdentity; 042import org.ametys.core.user.UserManager; 043import org.ametys.core.util.DateUtils; 044import org.ametys.plugins.explorer.calendars.EventRecurrenceTypeEnum; 045import org.ametys.plugins.messagingconnector.AbstractMessagingConnector; 046import org.ametys.plugins.messagingconnector.CalendarEvent; 047import org.ametys.plugins.messagingconnector.EmailMessage; 048import org.ametys.plugins.messagingconnector.MessagingConnectorException; 049import org.ametys.runtime.config.Config; 050 051import microsoft.exchange.webservices.data.core.ExchangeService; 052import microsoft.exchange.webservices.data.core.enumeration.availability.AvailabilityData; 053import microsoft.exchange.webservices.data.core.enumeration.misc.ConnectingIdType; 054import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion; 055import microsoft.exchange.webservices.data.core.enumeration.property.LegacyFreeBusyStatus; 056import microsoft.exchange.webservices.data.core.enumeration.property.MeetingResponseType; 057import microsoft.exchange.webservices.data.core.enumeration.property.WellKnownFolderName; 058import microsoft.exchange.webservices.data.core.enumeration.property.time.DayOfTheWeek; 059import microsoft.exchange.webservices.data.core.enumeration.search.LogicalOperator; 060import microsoft.exchange.webservices.data.core.enumeration.service.ConflictResolutionMode; 061import microsoft.exchange.webservices.data.core.enumeration.service.DeleteMode; 062import microsoft.exchange.webservices.data.core.enumeration.service.SendInvitationsMode; 063import microsoft.exchange.webservices.data.core.enumeration.service.SendInvitationsOrCancellationsMode; 064import microsoft.exchange.webservices.data.core.enumeration.service.ServiceResult; 065import microsoft.exchange.webservices.data.core.exception.service.remote.ServiceRequestException; 066import microsoft.exchange.webservices.data.core.exception.service.remote.ServiceResponseException; 067import microsoft.exchange.webservices.data.core.response.AttendeeAvailability; 068import microsoft.exchange.webservices.data.core.service.folder.CalendarFolder; 069import microsoft.exchange.webservices.data.core.service.folder.Folder; 070import microsoft.exchange.webservices.data.core.service.item.Appointment; 071import microsoft.exchange.webservices.data.core.service.item.Item; 072import microsoft.exchange.webservices.data.core.service.schema.EmailMessageSchema; 073import microsoft.exchange.webservices.data.credential.ExchangeCredentials; 074import microsoft.exchange.webservices.data.credential.WebCredentials; 075import microsoft.exchange.webservices.data.misc.ImpersonatedUserId; 076import microsoft.exchange.webservices.data.misc.availability.AttendeeInfo; 077import microsoft.exchange.webservices.data.misc.availability.GetUserAvailabilityResults; 078import microsoft.exchange.webservices.data.misc.availability.TimeWindow; 079import microsoft.exchange.webservices.data.property.complex.Attendee; 080import microsoft.exchange.webservices.data.property.complex.AttendeeCollection; 081import microsoft.exchange.webservices.data.property.complex.FolderId; 082import microsoft.exchange.webservices.data.property.complex.ItemId; 083import microsoft.exchange.webservices.data.property.complex.Mailbox; 084import microsoft.exchange.webservices.data.property.complex.MessageBody; 085import microsoft.exchange.webservices.data.property.complex.recurrence.pattern.Recurrence; 086import microsoft.exchange.webservices.data.property.complex.time.TimeZoneDefinition; 087import microsoft.exchange.webservices.data.search.CalendarView; 088import microsoft.exchange.webservices.data.search.FindItemsResults; 089import microsoft.exchange.webservices.data.search.ItemView; 090import microsoft.exchange.webservices.data.search.filter.SearchFilter; 091import microsoft.exchange.webservices.data.util.TimeZoneUtils; 092 093/** 094 * 095 * The connector used by the messaging connector plugin when the exchange mail 096 * server is used. Implements the methods of the MessagingConnector interface in 097 * order to get the informations from the mail server 098 * 099 */ 100public class ExchangeConnector extends AbstractMessagingConnector 101{ 102 /** The current user provider */ 103 protected CurrentUserProvider _currentUserProvider; 104 105 /** The user manager */ 106 private UserManager _userManager; 107 108 @Override 109 public void service(ServiceManager manager) throws ServiceException 110 { 111 super.service(manager); 112 _userManager = (UserManager) manager.lookup(UserManager.ROLE); 113 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 114 } 115 116 /** 117 * Get the service of connexion to the server exchange 118 * @param userIdentity The user identity 119 * @return the service 120 * @throws URISyntaxException if an error occurred 121 */ 122 protected ExchangeService getService(UserIdentity userIdentity) throws URISyntaxException 123 { 124 if (userIdentity == null) 125 { 126 return null; 127 } 128 129 String userName = Config.getInstance().getValueAsString("org.ametys.plugins.exchange.username"); 130 String password = Config.getInstance().getValueAsString("org.ametys.plugins.exchange.password"); 131 String url = Config.getInstance().getValueAsString("org.ametys.plugins.exchange.url"); 132 133 ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2); 134 ExchangeCredentials credentials = new WebCredentials(userName, password); 135 service.setCredentials(credentials); 136 137 String authMethod = Config.getInstance().getValueAsString("org.ametys.plugins.exchange.authmethod"); 138 139 if ("email".equals(authMethod)) 140 { 141 User user = _userManager.getUser(userIdentity); 142 String email = user.getEmail(); 143 if (StringUtils.isBlank(email)) 144 { 145 if (getLogger().isWarnEnabled()) 146 { 147 getLogger().warn("The user '" + userIdentity.getLogin() + "' has no email address set, thus exchange cannot be contacted using 'email' authentication method"); 148 } 149 return null; 150 } 151 service.setImpersonatedUserId(new ImpersonatedUserId(ConnectingIdType.SmtpAddress, email)); 152 } 153 else 154 { 155 service.setImpersonatedUserId(new ImpersonatedUserId(ConnectingIdType.PrincipalName, userIdentity.getLogin())); 156 } 157 158 service.setUrl(new URI(url)); 159 return service; 160 } 161 162 @Override 163 protected List<CalendarEvent> internalGetEvents(UserIdentity userIdentity, Date fromDate, Date untilDate, int maxEvents) throws MessagingConnectorException 164 { 165 try 166 { 167 List<CalendarEvent> calendar = new ArrayList<>(); 168 ExchangeService service = getService(userIdentity); 169 170 if (service != null) 171 { 172 // The search filter to get futur or not terminated events 173 CalendarFolder cf = CalendarFolder.bind(service, WellKnownFolderName.Calendar); 174 175 int maxDays = (int) DateUtils.asLocalDate(untilDate).toEpochDay() - (int) DateUtils.asLocalDate(fromDate).toEpochDay(); 176 GregorianCalendar gc = new GregorianCalendar(); 177 gc.add(Calendar.DATE, maxDays != 0 ? maxDays : 1000); 178 CalendarView calendarView = new CalendarView(new Date(), gc.getTime()); 179 FindItemsResults<Appointment> findResultsEvent = cf.findAppointments(calendarView); 180 181 calendarView.setMaxItemsReturned(maxEvents > 0 ? maxEvents : null); 182 findResultsEvent = cf.findAppointments(calendarView); 183 184 for (Appointment event : findResultsEvent.getItems()) 185 { 186 CalendarEvent newEvent = new CalendarEvent(); 187 newEvent.setStartDate(event.getStart()); 188 newEvent.setEndDate(event.getEnd()); 189 newEvent.setSubject(event.getSubject()); 190 newEvent.setLocation(event.getLocation()); 191 calendar.add(newEvent); 192 } 193 194 } 195 return calendar; 196 } 197 catch (Exception e) 198 { 199 throw new MessagingConnectorException("Failed to get the events for user " + userIdentity.toString(), e); 200 } 201 } 202 203 @Override 204 protected int internalGetEventsCount(UserIdentity userIdentity, Date fromDate, Date untilDate) throws MessagingConnectorException 205 { 206 try 207 { 208 int nextEventsCount = 0; 209 ExchangeService service = getService(userIdentity); 210 if (service != null) 211 { 212 // The search filter to get futur or not terminated events 213 CalendarFolder cf = CalendarFolder.bind(service, WellKnownFolderName.Calendar); 214 215 int maxDays = (int) DateUtils.asLocalDate(untilDate).toEpochDay() - (int) DateUtils.asLocalDate(fromDate).toEpochDay(); 216 GregorianCalendar gc = new GregorianCalendar(); 217 gc.add(Calendar.DATE, maxDays != 0 ? maxDays : 1000); 218 CalendarView calendarView = new CalendarView(new Date(), gc.getTime()); 219 FindItemsResults<Appointment> findResultsEvent = cf.findAppointments(calendarView); 220 nextEventsCount = findResultsEvent.getTotalCount(); 221 } 222 return nextEventsCount; 223 } 224 catch (Exception e) 225 { 226 throw new MessagingConnectorException("Failed to get the events count for user " + userIdentity.toString(), e); 227 } 228 } 229 230 @Override 231 protected List<EmailMessage> internalGetEmails(UserIdentity userIdentity, int maxEmails) throws MessagingConnectorException 232 { 233 try 234 { 235 List<EmailMessage> mailMessage = new ArrayList<>(); 236 237 ExchangeService service = getService(userIdentity); 238 239 if (service != null) 240 { 241 // The search filter to get unread email 242 SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false)); 243 ItemView view = new ItemView(maxEmails); 244 FindItemsResults<Item> findResultsMail = service.findItems(WellKnownFolderName.Inbox, sf, view); 245 246 List<Item> messagesReceived = findResultsMail.getItems(); 247 for (Item message : messagesReceived) 248 { 249 message.load(); 250 251 EmailMessage newMessage = new EmailMessage(); 252 newMessage.setSender(((microsoft.exchange.webservices.data.core.service.item.EmailMessage) message).getSender().getAddress()); 253 if (message.getSubject() != null) 254 { 255 newMessage.setSubject(message.getSubject()); 256 } 257 if (message.getBody() != null) 258 { 259 newMessage.setSummary(html2text(message.getBody().toString())); 260 } 261 mailMessage.add(newMessage); 262 } 263 } 264 return mailMessage; 265 } 266 catch (Exception e) 267 { 268 throw new MessagingConnectorException("Failed to get the emails for user " + userIdentity.toString(), e); 269 } 270 271 } 272 273 @Override 274 protected int internalGetEmailsCount(UserIdentity userIdentity) throws MessagingConnectorException 275 { 276 try 277 { 278 int emailsCount = 0; 279 280 ExchangeService service = getService(userIdentity); 281 282 if (service != null) 283 { 284 // The search filter to get unread email 285 SearchFilter sf = new SearchFilter.SearchFilterCollection(LogicalOperator.And, new SearchFilter.IsEqualTo(EmailMessageSchema.IsRead, false)); 286 ItemView view = new ItemView(20); 287 FindItemsResults<Item> findResultsMail = service.findItems(WellKnownFolderName.Inbox, sf, view); 288 289 emailsCount = findResultsMail.getTotalCount(); 290 } 291 return emailsCount; 292 } 293 catch (Exception e) 294 { 295 throw new MessagingConnectorException("Failed to get the emails for user " + userIdentity.toString(), e); 296 } 297 } 298 299 @Override 300 public boolean supportInvitation() throws MessagingConnectorException 301 { 302 return true; 303 } 304 305 @Override 306 public boolean isEventExist(String eventId, UserIdentity organiser) throws MessagingConnectorException 307 { 308 try 309 { 310 ExchangeService service = getService(organiser); 311 if (service != null) 312 { 313 ItemId itemId = new ItemId(eventId); 314 Appointment appointment = Appointment.bind(service, itemId); 315 316 return appointment != null; 317 } 318 } 319 catch (ServiceResponseException e) 320 { 321 return false; //Exchange doesn't find the event with id 'event Id' 322 } 323 catch (Exception e) 324 { 325 throw new MessagingConnectorException("Failed to get event " + eventId + " from organiser " + organiser.toString(), e); 326 } 327 328 return false; 329 } 330 331 @Override 332 public String createEvent(String title, String description, String place, boolean isAllDay, Date startDate, Date endDate, EventRecurrenceTypeEnum recurrenceType, Date untilDate, Map<String, Boolean> attendees, UserIdentity organiser) throws MessagingConnectorException 333 { 334 try 335 { 336 ExchangeService service = getService(organiser); 337 if (service != null) 338 { 339 Appointment appointment = new Appointment(service); 340 341 _setDataEvent(service, appointment, title, description, place, isAllDay, startDate, endDate, recurrenceType, untilDate, attendees); 342 343 User organiserUser = _userManager.getUser(organiser); 344 Mailbox mailBox = new Mailbox(organiserUser.getEmail()); 345 appointment.save(new FolderId(WellKnownFolderName.Calendar, mailBox), SendInvitationsMode.SendOnlyToAll); 346 347 return appointment.getId().getUniqueId(); 348 } 349 } 350 catch (Exception e) 351 { 352 throw new MessagingConnectorException("Failed to create event from organiser " + organiser.toString(), e); 353 } 354 355 return null; 356 } 357 358 @Override 359 public void updateEvent(String eventId, String title, String description, String place, boolean isAllDay, Date startDate, Date endDate, EventRecurrenceTypeEnum recurrenceType, Date untilDate, Map<String, Boolean> attendees, UserIdentity organiser) throws MessagingConnectorException 360 { 361 try 362 { 363 ExchangeService service = getService(organiser); 364 if (service != null) 365 { 366 ItemId itemId = new ItemId(eventId); 367 Appointment appointment = Appointment.bind(service, itemId); 368 369 _setDataEvent(service, appointment, title, description, place, isAllDay, startDate, endDate, recurrenceType, untilDate, attendees); 370 371 appointment.update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendOnlyToAll); 372 } 373 } 374 catch (Exception e) 375 { 376 throw new MessagingConnectorException("Failed to update event from organiser " + organiser.toString(), e); 377 } 378 } 379 380 private void _setDataEvent(ExchangeService service, Appointment appointment, String title, String description, String place, boolean isAllDay, Date startDate, Date endDate, EventRecurrenceTypeEnum recurrenceType, Date untilDate, Map<String, Boolean> attendees) throws Exception 381 { 382 TimeZone defaultTimeZone = TimeZone.getDefault(); 383 Map<String, String> olsonTimeZoneToMsMap = TimeZoneUtils.createOlsonTimeZoneToMsMap(); 384 String msTimeZoneId = olsonTimeZoneToMsMap.get(defaultTimeZone.getID()); 385 386 Collection<TimeZoneDefinition> serverTimeZones = service.getServerTimeZones(Collections.singletonList(msTimeZoneId)); 387 TimeZoneDefinition timeZone = serverTimeZones.iterator().next(); 388 389 appointment.setSubject(title); 390 appointment.setBody(new MessageBody(description)); 391 appointment.setStart(startDate); 392 if (isAllDay) 393 { 394 DateTime date = new DateTime(endDate); 395 appointment.setEnd(date.plusDays(1).toDate()); 396 } 397 else 398 { 399 appointment.setEnd(endDate); 400 } 401 appointment.setIsAllDayEvent(isAllDay); 402 appointment.setLocation(place); 403 appointment.setStartTimeZone(timeZone); 404 appointment.setEndTimeZone(timeZone); 405 406 _setRecurrence(appointment, startDate, recurrenceType, untilDate); 407 408 _setAttendees(appointment, attendees); 409 } 410 411 private void _setRecurrence(Appointment appointment, Date startDate, EventRecurrenceTypeEnum recurrenceType, Date untilDate) throws Exception 412 { 413 Recurrence recurrence = null; 414 switch (recurrenceType) 415 { 416 case ALL_DAY: 417 recurrence = new Recurrence.DailyPattern(startDate, 1); 418 break; 419 case ALL_WORKING_DAY: 420 String workingDayAsString = Config.getInstance().getValueAsString("org.ametys.plugins.explorer.calendar.event.working.day"); 421 422 List<DayOfTheWeek> days = new ArrayList<>(); 423 for (String idDay : StringUtils.split(workingDayAsString, ",")) 424 { 425 days.add(EnumUtils.getEnumList(DayOfTheWeek.class).get(Integer.parseInt(idDay) - 1)); 426 } 427 428 recurrence = new Recurrence.WeeklyPattern(startDate, 1, days.toArray(new DayOfTheWeek[days.size()])); 429 break; 430 case WEEKLY: 431 DateTime startWeeklyDateTime = new DateTime(startDate); 432 int dayOfWeekForWeekly = startWeeklyDateTime.getDayOfWeek(); 433 434 recurrence = new Recurrence.WeeklyPattern(startDate, 1, EnumUtils.getEnumList(DayOfTheWeek.class).get(dayOfWeekForWeekly % 7)); 435 break; 436 case BIWEEKLY: 437 DateTime startBiWeeklyDateTime = new DateTime(startDate); 438 int dayOfWeekForBiWeekly = startBiWeeklyDateTime.getDayOfWeek(); 439 440 recurrence = new Recurrence.WeeklyPattern(startDate, 2, EnumUtils.getEnumList(DayOfTheWeek.class).get(dayOfWeekForBiWeekly % 7)); 441 break; 442 case MONTHLY: 443 DateTime startMonthlyDateTime = new DateTime(startDate); 444 445 recurrence = new Recurrence.MonthlyPattern(startDate, 1, startMonthlyDateTime.getDayOfMonth()); 446 break; 447 case NEVER: 448 default: 449 //Still null 450 break; 451 } 452 453 if (untilDate != null && recurrence != null) 454 { 455 recurrence.setEndDate(untilDate); 456 appointment.setRecurrence(recurrence); 457 } 458 } 459 460 @Override 461 public void deleteEvent(String eventId, UserIdentity organiser) throws MessagingConnectorException 462 { 463 try 464 { 465 ExchangeService service = getService(organiser); 466 if (service != null) 467 { 468 ItemId itemId = new ItemId(eventId); 469 Appointment appointment = Appointment.bind(service, itemId); 470 appointment.delete(DeleteMode.MoveToDeletedItems); 471 } 472 } 473 catch (Exception e) 474 { 475 throw new MessagingConnectorException("Failed to delete event " + eventId + " with organiser " + organiser.toString(), e); 476 } 477 478 } 479 480 @Override 481 public Map<String, AttendeeInformation> getAttendees(String eventId, UserIdentity organiser) throws MessagingConnectorException 482 { 483 Map<String, AttendeeInformation> attendees = new HashMap<>(); 484 try 485 { 486 ExchangeService service = getService(organiser); 487 if (service != null) 488 { 489 ItemId itemId = new ItemId(eventId); 490 Appointment appointment = Appointment.bind(service, itemId); 491 492 for (Attendee attendee : appointment.getRequiredAttendees()) 493 { 494 ResponseType responseStatus = _getResponseStatus(attendee.getResponseType()); 495 AttendeeInformation attendeeInformation = new AttendeeInformation(true, responseStatus); 496 attendees.put(attendee.getAddress(), attendeeInformation); 497 } 498 499 for (Attendee attendee : appointment.getOptionalAttendees()) 500 { 501 ResponseType responseStatus = _getResponseStatus(attendee.getResponseType()); 502 AttendeeInformation attendeeInformation = new AttendeeInformation(false, responseStatus); 503 attendees.put(attendee.getAddress(), attendeeInformation); 504 } 505 } 506 } 507 catch (ServiceResponseException e) 508 { 509 return attendees; //Exchange doesn't find the event with id 'event Id' 510 } 511 catch (Exception e) 512 { 513 throw new MessagingConnectorException("Failed to get attendees from event " + eventId + " with organiser " + organiser.toString(), e); 514 } 515 516 return attendees; 517 } 518 519 @Override 520 public void setAttendees(String eventId, Map<String, Boolean> attendees, UserIdentity organiser) throws MessagingConnectorException 521 { 522 try 523 { 524 ExchangeService service = getService(organiser); 525 if (service != null) 526 { 527 ItemId itemId = new ItemId(eventId); 528 Appointment appointment = Appointment.bind(service, itemId); 529 530 _setAttendees(appointment, attendees); 531 532 appointment.update(ConflictResolutionMode.AlwaysOverwrite, SendInvitationsOrCancellationsMode.SendOnlyToChanged); 533 } 534 } 535 catch (Exception e) 536 { 537 throw new MessagingConnectorException("Failed to get attendees from event " + eventId + " with organiser " + organiser.toString(), e); 538 } 539 } 540 541 @Override 542 public Map<String, FreeBusyStatus> getFreeBusy(Date startDate, Date endDate, boolean isAllDay, Set<String> attendees, UserIdentity organiser) throws MessagingConnectorException 543 { 544 Map<String, FreeBusyStatus> attendeesMap = new HashMap<>(); 545 if (attendees.isEmpty()) 546 { 547 return attendeesMap; 548 } 549 550 try 551 { 552 ExchangeService service = getService(organiser); 553 if (service != null) 554 { 555 TimeWindow timeWindow = null; 556 if (isAllDay) 557 { 558 DateTime endDateTime = new DateTime(endDate); 559 timeWindow = new TimeWindow(startDate, endDateTime.plusDays(1).toDate()); 560 } 561 else 562 { 563 DateTime startDateTime = new DateTime(startDate); 564 DateTime endDateTime = new DateTime(endDate); 565 timeWindow = new TimeWindow(startDateTime.minusDays(1).toDate(), endDateTime.plusDays(1).toDate()); 566 } 567 568 List<AttendeeInfo> attendeesInfo = new ArrayList<>(); 569 for (String email : attendees) 570 { 571 attendeesInfo.add(new AttendeeInfo(email)); 572 } 573 574 GetUserAvailabilityResults userAvailability = service.getUserAvailability(attendeesInfo, timeWindow, AvailabilityData.FreeBusy); 575 int index = 0; 576 for (AttendeeAvailability availability : userAvailability.getAttendeesAvailability()) 577 { 578 AttendeeInfo attendeeInfo = attendeesInfo.get(index); 579 String email = attendeeInfo.getSmtpAddress(); 580 581 FreeBusyStatus freeBusyStatus = FreeBusyStatus.Unknown; 582 if (!ServiceResult.Error.equals(availability.getResult())) 583 { 584 freeBusyStatus = FreeBusyStatus.Free; 585 for (microsoft.exchange.webservices.data.property.complex.availability.CalendarEvent calEvent : availability.getCalendarEvents()) 586 { 587 if (isAllDay) 588 { 589 if (calEvent.getFreeBusyStatus().equals(LegacyFreeBusyStatus.Busy)) 590 { 591 freeBusyStatus = FreeBusyStatus.Busy; 592 } 593 } 594 else 595 { 596 if (calEvent.getFreeBusyStatus().equals(LegacyFreeBusyStatus.Busy) && startDate.before(calEvent.getEndTime()) && endDate.after(calEvent.getStartTime())) 597 { 598 freeBusyStatus = FreeBusyStatus.Busy; 599 } 600 } 601 } 602 } 603 604 attendeesMap.put(email, freeBusyStatus); 605 index++; 606 } 607 } 608 } 609 catch (Exception e) 610 { 611 throw new MessagingConnectorException("Failed to get free/busy with organiser " + organiser.toString(), e); 612 } 613 614 return attendeesMap; 615 } 616 617 @Override 618 public boolean isUserExist(UserIdentity userIdentity) throws MessagingConnectorException 619 { 620 try 621 { 622 ExchangeService service = getService(userIdentity); 623 if (service != null) 624 { 625 Folder.bind(service, WellKnownFolderName.Inbox); 626 return true; 627 } 628 629 return false; 630 } 631 catch (ServiceRequestException e) 632 { 633 return false; 634 } 635 catch (Exception e) 636 { 637 throw new MessagingConnectorException("Failed to know if user " + userIdentity.getLogin() + " exist in exchange", e); 638 } 639 } 640 641 private ResponseType _getResponseStatus(MeetingResponseType meetingResponseType) 642 { 643 switch (meetingResponseType) 644 { 645 case Accept: 646 return ResponseType.Accept; 647 case Decline: 648 return ResponseType.Decline; 649 case Tentative: 650 return ResponseType.Maybe; 651 default: 652 return ResponseType.Unknown; 653 } 654 } 655 656 private void _setAttendees(Appointment appointment, Map<String, Boolean> attendees) throws Exception 657 { 658 if (attendees != null) 659 { 660 AttendeeCollection requiredAttendees = appointment.getRequiredAttendees(); 661 AttendeeCollection optionalAttendees = appointment.getOptionalAttendees(); 662 663 requiredAttendees.clear(); 664 optionalAttendees.clear(); 665 for (String email : attendees.keySet()) 666 { 667 boolean isMandatory = attendees.get(email); 668 if (isMandatory) 669 { 670 requiredAttendees.add(new Attendee(email)); 671 } 672 else 673 { 674 optionalAttendees.add(new Attendee(email)); 675 } 676 } 677 } 678 } 679 680 /** 681 * Converts a given html String into a plain text String 682 * @param html the html String that will be converted 683 * @return a String plain text of the given html 684 */ 685 protected static String html2text(String html) 686 { 687 return Jsoup.parse(html).text(); 688 } 689}