@Override
 protected void sendReminder(CalendarItem calItem, Invite invite) throws Exception {
   Account account = calItem.getAccount();
   Locale locale = account.getLocale();
   TimeZone tz = Util.getAccountTimeZone(account);
   MimeMessage mm = new Mime.FixedMimeMessage(JMSession.getSmtpSession(account));
   String to = account.getAttr(Provisioning.A_zimbraCalendarReminderDeviceEmail);
   if (to == null) {
     ZimbraLog.scheduler.info(
         "Unable to send calendar reminder sms since %s is not set",
         Provisioning.A_zimbraCalendarReminderDeviceEmail);
     return;
   }
   mm.setRecipient(javax.mail.Message.RecipientType.TO, new JavaMailInternetAddress(to));
   mm.setText(getText(calItem, invite, locale, tz), MimeConstants.P_CHARSET_UTF8);
   mm.saveChanges();
   MailSender mailSender = calItem.getMailbox().getMailSender();
   mailSender.setSaveToSent(false);
   mailSender.sendMimeMessage(null, calItem.getMailbox(), mm);
 }
  public static FreeBusy getWorkingHours(
      Account authAcct, boolean asAdmin, Account account, String name, long start, long end)
      throws ServiceException {
    // If free/busy viewing is blocked, so is viewing working hours.
    AccessManager accessMgr = AccessManager.getInstance();
    boolean accountAceAllowed = accessMgr.canDo(authAcct, account, User.R_viewFreeBusy, asAdmin);
    if (!accountAceAllowed) return FreeBusy.nodataFreeBusy(account.getName(), start, end);

    // Get the working hours preference and parse it.
    String workingHoursPref = account.getPrefCalendarWorkingHours();
    HoursByDay workingHoursByDay = new HoursByDay(workingHoursPref);

    // Build a recurrence rule for each day of the week and expand over the time range.
    IntervalList intervals = new IntervalList(start, end);
    ICalTimeZone tz = Util.getAccountTimeZone(account);
    TimeZoneMap tzmap = new TimeZoneMap(tz);
    StartSpec startSpec = new StartSpec(start, tz);
    for (int day = 1; day <= 7; ++day) {
      TimeRange timeRange = workingHoursByDay.getHoursForDay(day);
      if (timeRange.enabled) {
        IRecurrence rrule = getRecurrenceForDay(day, startSpec, timeRange, tz, tzmap);
        List<Instance> instances = rrule.expandInstances(0, start, end);
        for (Instance inst : instances) {
          Interval ival =
              new Interval(inst.getStart(), inst.getEnd(), IcalXmlStrMap.FBTYPE_BUSY_UNAVAILABLE);
          intervals.addInterval(ival);
        }
      }
    }
    // Invert FREE and BUSY_UNAVAILABLE in the intervals so that working hours are displayed as free
    // and non-working
    // hours are shown as out-of-office.
    for (Iterator<Interval> iter = intervals.iterator(); iter.hasNext(); ) {
      Interval interval = iter.next();
      String status = interval.getStatus();
      interval.setStatus(invertStatus(status));
    }
    return new FreeBusy(name, intervals, start, end);
  }