use of com.zimbra.common.calendar.ZCalendar.ZComponent in project zm-mailbox by Zimbra.
the class TestCalDav method testFuzzyTimeZoneMatchGMT_06.
@Test
public void testFuzzyTimeZoneMatchGMT_06() throws Exception {
try (ByteArrayInputStream bais = new ByteArrayInputStream(VtimeZoneGMT_0600_0500.getBytes())) {
ZVCalendar tzcal = ZCalendar.ZCalendarBuilder.build(bais, MimeConstants.P_CHARSET_UTF8);
assertNotNull("tzcal", tzcal);
ZComponent tzcomp = tzcal.getComponent(ICalTok.VTIMEZONE);
assertNotNull("tzcomp", tzcomp);
ICalTimeZone tz = ICalTimeZone.fromVTimeZone(tzcomp, false, /* skipLookup */
ICalTimeZone.TZID_NAME_ASSIGNMENT_BEHAVIOR.ALWAYS_KEEP);
ICalTimeZone matchtz = ICalTimeZone.lookupMatchingWellKnownTZ(tz);
assertEquals("ID of Timezone which fuzzy matches GMT=06.00/-05.00", "America/Chicago", matchtz.getID());
}
}
use of com.zimbra.common.calendar.ZCalendar.ZComponent in project zm-mailbox by Zimbra.
the class Mailbox method writeICalendarForCalendarItems.
public void writeICalendarForCalendarItems(Writer writer, OperationContext octxt, Collection<CalendarItem> calItems, Folder f, boolean useOutlookCompatMode, boolean ignoreErrors, boolean needAppleICalHacks, boolean trimCalItemsList, boolean escapeHtmlTags, boolean includeAttaches) throws ServiceException {
lock.lock();
try {
writer.write("BEGIN:VCALENDAR\r\n");
if (f != null) {
writer.write("X-WR-CALNAME:");
writer.write(f.getName());
writer.write("\r\n");
writer.write("X-WR-CALID:");
writer.write(new ItemId(f).toString());
writer.write("\r\n");
}
ZProperty prop;
prop = new ZProperty(ICalTok.PRODID, ZCalendar.sZimbraProdID);
prop.toICalendar(writer, needAppleICalHacks);
prop = new ZProperty(ICalTok.VERSION, ZCalendar.sIcalVersion);
prop.toICalendar(writer, needAppleICalHacks);
prop = new ZProperty(ICalTok.METHOD, ICalTok.PUBLISH.toString());
prop.toICalendar(writer, needAppleICalHacks);
// timezones
ICalTimeZone localTz = Util.getAccountTimeZone(getAccount());
TimeZoneMap tzmap = new TimeZoneMap(localTz);
for (CalendarItem calItem : calItems) {
tzmap.add(calItem.getTimeZoneMap());
}
// iterate the tzmap and add all the VTimeZone's
for (Iterator<ICalTimeZone> iter = tzmap.tzIterator(); iter.hasNext(); ) {
ICalTimeZone tz = iter.next();
tz.newToVTimeZone().toICalendar(writer, needAppleICalHacks);
}
// help keep memory consumption low
tzmap = null;
// build all the event components and add them to the Calendar
for (Iterator<CalendarItem> iter = calItems.iterator(); iter.hasNext(); ) {
CalendarItem calItem = iter.next();
boolean allowPrivateAccess = calItem.isPublic() || calItem.allowPrivateAccess(octxt.getAuthenticatedUser(), octxt.isUsingAdminPrivileges());
if (trimCalItemsList) {
// help keep memory consumption low
iter.remove();
}
Invite[] invites = calItem.getInvites();
if (invites != null && invites.length > 0) {
boolean appleICalExdateHack = LC.calendar_apple_ical_compatible_canceled_instances.booleanValue();
ZComponent[] comps = null;
try {
comps = Invite.toVComponents(invites, allowPrivateAccess, useOutlookCompatMode, appleICalExdateHack, includeAttaches);
} catch (ServiceException e) {
if (ignoreErrors) {
ZimbraLog.calendar.warn("Error retrieving iCalendar data for item %s: %s", calItem.getId(), e.getMessage(), e);
} else {
throw e;
}
}
if (comps != null) {
for (ZComponent comp : comps) {
comp.toICalendar(writer, needAppleICalHacks, escapeHtmlTags);
}
}
}
}
writer.write("END:VCALENDAR\r\n");
} catch (IOException e) {
throw ServiceException.FAILURE("Error writing iCalendar", e);
} finally {
lock.release();
}
}
use of com.zimbra.common.calendar.ZCalendar.ZComponent in project zm-mailbox by Zimbra.
the class ScheduleOutbox method adjustOrganizer.
/**
* For Vanilla CalDAV access where Apple style delegation has not been enabled, attempts by the delegate
* to use a shared calendar acting as themselves are translated to appear as if acting as a delegate,
* otherwise the experience can be very poor.
* @throws ServiceException
*/
private void adjustOrganizer(DavContext ctxt, ZCalendar.ZVCalendar cal, ZComponent req, DelegationInfo delegationInfo) throws ServiceException {
// BusyCal 2.5.3 seems to post with the wrong organizer even if ical delegation is switched on - even though
// it uses the right ORGANIZER in the calendar entry.
// if (ctxt.useIcalDelegation()) { return; }
Mailbox mbox = MailboxManager.getInstance().getMailboxByAccount(ctxt.getAuthAccount());
String uid = req.getPropVal(ICalTok.UID, null);
CalendarItem matchingCalendarEntry = mbox.getCalendarItemByUid(ctxt.getOperationContext(), uid);
if (matchingCalendarEntry == null) {
List<com.zimbra.cs.mailbox.Mountpoint> sharedCalendars = mbox.getCalendarMountpoints(ctxt.getOperationContext(), SortBy.NONE);
if (sharedCalendars == null) {
// Can't work out anything useful
return;
}
Set<Account> accts = Sets.newHashSet();
for (com.zimbra.cs.mailbox.Mountpoint sharedCalendar : sharedCalendars) {
accts.add(Provisioning.getInstance().get(AccountBy.id, sharedCalendar.getOwnerId()));
}
for (Account acct : accts) {
Mailbox sbox = MailboxManager.getInstance().getMailboxByAccount(acct);
matchingCalendarEntry = sbox.getCalendarItemByUid(ctxt.getOperationContext(), uid);
if (matchingCalendarEntry != null) {
break;
}
}
}
if (matchingCalendarEntry == null) {
return;
}
Invite[] invites = matchingCalendarEntry.getInvites();
if (invites == null) {
return;
}
for (Invite inv : invites) {
ZOrganizer org = inv.getOrganizer();
if (org != null) {
delegationInfo.setOwner(org.getAddress());
if (Strings.isNullOrEmpty(org.getCn())) {
Account ownerAcct = Provisioning.getInstance().get(AccountBy.name, org.getAddress());
if (!Strings.isNullOrEmpty(ownerAcct.getDisplayName())) {
delegationInfo.setOwnerCn(ownerAcct.getDisplayName());
}
} else {
delegationInfo.setOwnerCn(org.getCn());
}
break;
}
}
if (delegationInfo.getOwner() == null) {
return;
}
AccountAddressMatcher acctMatcher = new AccountAddressMatcher(ctxt.getAuthAccount());
boolean originatorIsCalEntryOrganizer = acctMatcher.matches(delegationInfo.getOwnerEmail());
if (originatorIsCalEntryOrganizer) {
return;
}
for (ZComponent component : cal.getComponents()) {
ZProperty organizerProp = component.getProperty(ICalTok.ORGANIZER);
if (organizerProp != null) {
organizerProp.setValue(delegationInfo.getOwner());
ZParameter cn = organizerProp.getParameter(ICalTok.CN);
if (cn == null) {
organizerProp.addParameter(new ZParameter(ICalTok.CN, delegationInfo.getOwnerCn()));
} else {
cn.setValue(delegationInfo.getOwnerCn());
}
ZParameter sentBy = organizerProp.getParameter(ICalTok.SENT_BY);
if (sentBy == null) {
organizerProp.addParameter(new ZParameter(ICalTok.SENT_BY, delegationInfo.getOriginator()));
} else {
sentBy.setValue(delegationInfo.getOriginator());
}
}
}
}
use of com.zimbra.common.calendar.ZCalendar.ZComponent in project zm-mailbox by Zimbra.
the class ScheduleOutbox method handlePost.
@Override
public void handlePost(DavContext ctxt) throws DavException, IOException, ServiceException {
DelegationInfo delegationInfo = new DelegationInfo(ctxt.getRequest().getHeader(DavProtocol.HEADER_ORIGINATOR));
Enumeration<String> recipients = ctxt.getRequest().getHeaders(DavProtocol.HEADER_RECIPIENT);
InputStream in = ctxt.getUpload().getInputStream();
ZCalendar.ZVCalendar vcalendar = ZCalendar.ZCalendarBuilder.build(in, MimeConstants.P_CHARSET_UTF8);
Closeables.closeQuietly(in);
Iterator<ZComponent> iter = vcalendar.getComponentIterator();
ZComponent req = null;
while (iter.hasNext()) {
req = iter.next();
if (req.getTok() != ICalTok.VTIMEZONE)
break;
req = null;
}
if (req == null) {
throw new DavException("empty request", HttpServletResponse.SC_BAD_REQUEST);
}
ZimbraLog.dav.debug("originator: %s", delegationInfo.getOriginator());
boolean isVEventOrVTodo = ICalTok.VEVENT.equals(req.getTok()) || ICalTok.VTODO.equals(req.getTok());
boolean isOrganizerMethod = false, isCancel = false;
if (isVEventOrVTodo) {
String method = vcalendar.getPropVal(ICalTok.METHOD, null);
if (method != null) {
isOrganizerMethod = Invite.isOrganizerMethod(method);
isCancel = ICalTok.CANCEL.toString().equalsIgnoreCase(method);
;
}
// Apple iCal fixup
CalDavUtils.removeAttendeeForOrganizer(req);
}
// Get organizer and list of attendees. (mailto:email values)
ArrayList<String> attendees = new ArrayList<String>();
String organizer = null;
for (Iterator<ZProperty> propsIter = req.getPropertyIterator(); propsIter.hasNext(); ) {
ZProperty prop = propsIter.next();
ICalTok token = prop.getToken();
if (ICalTok.ATTENDEE.equals(token)) {
String val = prop.getValue();
if (val != null) {
attendees.add(val.trim());
}
} else if (ICalTok.ORGANIZER.equals(token)) {
String val = prop.getValue();
if (val != null) {
organizer = val.trim();
String addr = CalDavUtils.stripMailto(organizer);
// Rewrite the alias to primary address
Account acct = Provisioning.getInstance().get(AccountBy.name, addr);
if (acct != null) {
String newAddr = acct.getName();
if (!addr.equals(newAddr)) {
organizer = "mailto:" + newAddr;
prop.setValue(organizer);
}
}
}
}
}
// Apple iCal is very inconsistent about the user's identity when the account has aliases.
if (isVEventOrVTodo && delegationInfo.getOriginator() != null && ctxt.getAuthAccount() != null) {
AccountAddressMatcher acctMatcher = new AccountAddressMatcher(ctxt.getAuthAccount());
if (acctMatcher.matches(delegationInfo.getOriginatorEmail())) {
if (isOrganizerMethod) {
if (organizer != null) {
String organizerEmail = CalDavUtils.stripMailto(organizer);
if (!organizerEmail.equalsIgnoreCase(delegationInfo.getOriginatorEmail()) && acctMatcher.matches(organizerEmail)) {
delegationInfo.setOriginator(organizer);
ZimbraLog.dav.debug("changing originator to %s to match address/alias used in ORGANIZER", delegationInfo.getOriginator());
}
}
} else {
for (String at : attendees) {
String atEmail = CalDavUtils.stripMailto(at);
if (delegationInfo.getOriginatorEmail().equalsIgnoreCase(atEmail)) {
break;
} else if (acctMatcher.matches(atEmail)) {
delegationInfo.setOriginator(at);
ZimbraLog.dav.debug("changing originator to %s to match address/alias used in ATTENDEE", delegationInfo.getOriginator());
break;
}
}
}
}
}
// Get the recipients.
ArrayList<String> rcptArray = new ArrayList<String>();
while (recipients.hasMoreElements()) {
String rcptHdr = recipients.nextElement();
String[] rcpts = null;
if (rcptHdr.indexOf(',') > 0) {
rcpts = rcptHdr.split(",");
} else {
rcpts = new String[] { rcptHdr };
}
for (String rcpt : rcpts) {
if (rcpt != null) {
rcpt = rcpt.trim();
if (rcpt.length() != 0) {
// Workaround for Apple iCal: Ignore attendees with address "invalid:nomail".
if (rcpt.equalsIgnoreCase("invalid:nomail")) {
continue;
}
if (isVEventOrVTodo) {
// iCal can sometimes do that when organizer account has aliases.
if (isOrganizerMethod && rcpt.equalsIgnoreCase(organizer)) {
continue;
}
// as ATTENDEE in the CANCEL component being sent. (iCal does that part correctly, at least.)
if (isCancel) {
boolean isAttendee = false;
// Rcpt must be an attendee of the cancel component.
for (String at : attendees) {
if (rcpt.equalsIgnoreCase(at)) {
isAttendee = true;
break;
}
}
if (!isAttendee) {
ZimbraLog.dav.info("Ignoring non-attendee recipient '%s' of CANCEL request; likely a client bug", rcpt);
continue;
}
}
}
// All checks passed.
rcptArray.add(rcpt);
}
}
}
}
Element scheduleResponse = ctxt.getDavResponse().getTop(DavElements.E_SCHEDULE_RESPONSE);
for (String rcpt : rcptArray) {
ZimbraLog.dav.debug("recipient email: " + rcpt);
Element resp = scheduleResponse.addElement(DavElements.E_CALDAV_RESPONSE);
switch(req.getTok()) {
case VFREEBUSY:
handleFreebusyRequest(ctxt, req, delegationInfo.getOriginator(), rcpt, resp);
break;
case VEVENT:
// records.
if (isOrganizerMethod) {
adjustOrganizer(ctxt, vcalendar, req, delegationInfo);
}
validateRequest(isOrganizerMethod, delegationInfo, organizer, ctxt, req);
handleEventRequest(ctxt, vcalendar, req, delegationInfo, rcpt, resp);
break;
default:
throw new DavException("unrecognized request: " + req.getTok(), HttpServletResponse.SC_BAD_REQUEST);
}
}
}
use of com.zimbra.common.calendar.ZCalendar.ZComponent in project zm-mailbox by Zimbra.
the class CalendarCollection method findSummary.
private String findSummary(ZVCalendar cal) {
Iterator<ZComponent> iter = cal.getComponentIterator();
while (iter.hasNext()) {
ZComponent comp = iter.next();
String summary = comp.getPropVal(ICalTok.SUMMARY, null);
if (summary != null)
return summary;
}
return "calendar event";
}
Aggregations