Compare commits
34
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c04f5a4775 | ||
|
|
0ce90d1707 | ||
|
|
ed6a2a6a88 | ||
|
|
9b312f8b0a | ||
|
|
1b3304c193 | ||
|
|
5f04b065cd | ||
|
|
3e1cd079a8 | ||
|
|
b5e77ad86c | ||
|
|
5bc0a0a932 | ||
|
|
582af53af0 | ||
|
|
13f01b512b | ||
|
|
cdb25b141d | ||
|
|
a9868b1c93 | ||
|
|
2cf66e037d | ||
|
|
449d838dc2 | ||
|
|
c4bc215a47 | ||
|
|
c9936d7ecf | ||
|
|
885e59a2af | ||
|
|
bf398889bf | ||
|
|
e26e3d7307 | ||
|
|
045b275b27 | ||
|
|
7ec1973e0f | ||
|
|
a79a9c4eff | ||
|
|
f049e2430a | ||
|
|
59b3219f2d | ||
|
|
e9eb8bdc86 | ||
|
|
5e0c7ae4f2 | ||
|
|
c1c0c1ab44 | ||
|
|
a59fff785b | ||
|
|
6a70db80e6 | ||
|
|
d610630c8d | ||
|
|
4dc7790015 | ||
|
|
9dd000a2ca | ||
|
|
ce4084e528 |
No files matched your search
+9
-29
@@ -1,33 +1,13 @@
|
||||
*._*
|
||||
*.css
|
||||
*.pyc
|
||||
*.sax
|
||||
*.swp
|
||||
*.wox/
|
||||
*/*/*.SOGo/
|
||||
*/*/*/obj/
|
||||
*/*/obj/
|
||||
config.make
|
||||
tags
|
||||
*/obj/
|
||||
.scss-lint-config.yml_
|
||||
Documentation/*.docbook
|
||||
Documentation/*.pdf
|
||||
*/*/obj/
|
||||
*/*/*/obj/
|
||||
*/*/*.SOGo/
|
||||
*.sax
|
||||
*.wox/
|
||||
*.swp
|
||||
SoObjects/SOGo/SOGo.framework/
|
||||
SoObjects/SOGo/derived_src/
|
||||
Tests/*/config.py
|
||||
UI/WebServerResources/.bowerrc
|
||||
UI/WebServerResources/.sass-cache/
|
||||
UI/WebServerResources/bower_components/
|
||||
UI/WebServerResources/css/
|
||||
UI/WebServerResources/css/styles.css
|
||||
UI/WebServerResources/css/styles.css.map
|
||||
UI/WebServerResources/js/Common.js*
|
||||
UI/WebServerResources/js/Contacts.js*
|
||||
UI/WebServerResources/js/Mailer.js*
|
||||
UI/WebServerResources/js/Preferences.js*
|
||||
UI/WebServerResources/js/Scheduler.js*
|
||||
UI/WebServerResources/js/vendor/
|
||||
UI/WebServerResources/node_modules/
|
||||
UI/WebServerResources/scss/.sass-cache/
|
||||
config.make
|
||||
doc
|
||||
tags
|
||||
*.pyc
|
||||
@@ -1,3 +0,0 @@
|
||||
[submodule "UI/WebServerResources/angular-material"]
|
||||
path = UI/WebServerResources/angular-material
|
||||
url = https://github.com/angular/material
|
||||
-59
@@ -12,7 +12,6 @@ trans.da_DK = UI/MailerUI/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/MailerUI/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/MailerUI/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/MailerUI/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/MailerUI/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/MailerUI/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/MailerUI/French.lproj/Localizable.strings
|
||||
trans.hu = UI/MailerUI/Hungarian.lproj/Localizable.strings
|
||||
@@ -25,10 +24,8 @@ trans.pl = UI/MailerUI/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/MailerUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/MailerUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/MailerUI/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/MailerUI/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/MailerUI/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/MailerUI/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/MailerUI/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-preferencesui]
|
||||
source_file = UI/PreferencesUI/English.lproj/Localizable.strings
|
||||
@@ -41,7 +38,6 @@ trans.da_DK = UI/PreferencesUI/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/PreferencesUI/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/PreferencesUI/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/PreferencesUI/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/PreferencesUI/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/PreferencesUI/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/PreferencesUI/French.lproj/Localizable.strings
|
||||
trans.hu = UI/PreferencesUI/Hungarian.lproj/Localizable.strings
|
||||
@@ -54,10 +50,8 @@ trans.pl = UI/PreferencesUI/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/PreferencesUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/PreferencesUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/PreferencesUI/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/PreferencesUI/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/PreferencesUI/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/PreferencesUI/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/PreferencesUI/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-scheduler]
|
||||
source_file = UI/Scheduler/English.lproj/Localizable.strings
|
||||
@@ -70,7 +64,6 @@ trans.da_DK = UI/Scheduler/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/Scheduler/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/Scheduler/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/Scheduler/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/Scheduler/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/Scheduler/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/Scheduler/French.lproj/Localizable.strings
|
||||
trans.hu = UI/Scheduler/Hungarian.lproj/Localizable.strings
|
||||
@@ -83,10 +76,8 @@ trans.pl = UI/Scheduler/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/Scheduler/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/Scheduler/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/Scheduler/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/Scheduler/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/Scheduler/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/Scheduler/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/Scheduler/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-contacts]
|
||||
source_file = UI/Contacts/English.lproj/Localizable.strings
|
||||
@@ -99,7 +90,6 @@ trans.da_DK = UI/Contacts/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/Contacts/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/Contacts/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/Contacts/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/Contacts/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/Contacts/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/Contacts/French.lproj/Localizable.strings
|
||||
trans.hu = UI/Contacts/Hungarian.lproj/Localizable.strings
|
||||
@@ -112,10 +102,8 @@ trans.pl = UI/Contacts/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/Contacts/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/Contacts/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/Contacts/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/Contacts/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/Contacts/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/Contacts/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/Contacts/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-mainui]
|
||||
source_file = UI/MainUI/English.lproj/Localizable.strings
|
||||
@@ -128,7 +116,6 @@ trans.da_DK = UI/MainUI/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/MainUI/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/MainUI/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/MainUI/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/MainUI/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/MainUI/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/MainUI/French.lproj/Localizable.strings
|
||||
trans.hu = UI/MainUI/Hungarian.lproj/Localizable.strings
|
||||
@@ -141,10 +128,8 @@ trans.pl = UI/MainUI/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/MainUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/MainUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/MainUI/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/MainUI/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/MainUI/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/MainUI/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/MainUI/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-common]
|
||||
source_file = UI/Common/English.lproj/Localizable.strings
|
||||
@@ -157,7 +142,6 @@ trans.da_DK = UI/Common/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/Common/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/Common/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/Common/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/Common/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/Common/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/Common/French.lproj/Localizable.strings
|
||||
trans.hu = UI/Common/Hungarian.lproj/Localizable.strings
|
||||
@@ -170,10 +154,8 @@ trans.pl = UI/Common/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/Common/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/Common/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/Common/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/Common/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/Common/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/Common/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/Common/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-administrationui]
|
||||
source_file = UI/AdministrationUI/English.lproj/Localizable.strings
|
||||
@@ -186,7 +168,6 @@ trans.da_DK = UI/AdministrationUI/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/AdministrationUI/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/AdministrationUI/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/AdministrationUI/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/AdministrationUI/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/AdministrationUI/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/AdministrationUI/French.lproj/Localizable.strings
|
||||
trans.hu = UI/AdministrationUI/Hungarian.lproj/Localizable.strings
|
||||
@@ -199,10 +180,8 @@ trans.pl = UI/AdministrationUI/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/AdministrationUI/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/AdministrationUI/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/AdministrationUI/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/AdministrationUI/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/AdministrationUI/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/AdministrationUI/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/AdministrationUI/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.soobjects-appointments]
|
||||
source_file = SoObjects/Appointments/English.lproj/Localizable.strings
|
||||
@@ -215,7 +194,6 @@ trans.da_DK = SoObjects/Appointments/Danish.lproj/Localizable.strings
|
||||
trans.de = SoObjects/Appointments/German.lproj/Localizable.strings
|
||||
trans.es_AR = SoObjects/Appointments/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = SoObjects/Appointments/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = SoObjects/Appointments/Basque.lproj/Localizable.strings
|
||||
trans.fi = SoObjects/Appointments/Finnish.lproj/Localizable.strings
|
||||
trans.fr = SoObjects/Appointments/French.lproj/Localizable.strings
|
||||
trans.hu = SoObjects/Appointments/Hungarian.lproj/Localizable.strings
|
||||
@@ -228,10 +206,8 @@ trans.pl = SoObjects/Appointments/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = SoObjects/Appointments/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = SoObjects/Appointments/Russian.lproj/Localizable.strings
|
||||
trans.sk = SoObjects/Appointments/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = SoObjects/Appointments/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = SoObjects/Appointments/Swedish.lproj/Localizable.strings
|
||||
trans.uk = SoObjects/Appointments/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = SoObjects/Appointments/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.soobjects-contacts]
|
||||
source_file = SoObjects/Contacts/English.lproj/Localizable.strings
|
||||
@@ -244,7 +220,6 @@ trans.da_DK = SoObjects/Contacts/Danish.lproj/Localizable.strings
|
||||
trans.de = SoObjects/Contacts/German.lproj/Localizable.strings
|
||||
trans.es_AR = SoObjects/Contacts/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = SoObjects/Contacts/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = SoObjects/Contacts/Basque.lproj/Localizable.strings
|
||||
trans.fi = SoObjects/Contacts/Finnish.lproj/Localizable.strings
|
||||
trans.fr = SoObjects/Contacts/French.lproj/Localizable.strings
|
||||
trans.hu = SoObjects/Contacts/Hungarian.lproj/Localizable.strings
|
||||
@@ -257,39 +232,8 @@ trans.pl = SoObjects/Contacts/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = SoObjects/Contacts/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = SoObjects/Contacts/Russian.lproj/Localizable.strings
|
||||
trans.sk = SoObjects/Contacts/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = SoObjects/Contacts/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = SoObjects/Contacts/Swedish.lproj/Localizable.strings
|
||||
trans.uk = SoObjects/Contacts/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = SoObjects/Contacts/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.soobjects-mailer]
|
||||
source_file = SoObjects/Mailer/English.lproj/Localizable.strings
|
||||
source_lang = en
|
||||
trans.ar = SoObjects/Mailer/Arabic.lproj/Localizable.strings
|
||||
trans.ca = SoObjects/Mailer/Catalan.lproj/Localizable.strings
|
||||
trans.cs = SoObjects/Mailer/Czech.lproj/Localizable.strings
|
||||
trans.cy = SoObjects/Mailer/Welsh.lproj/Localizable.strings
|
||||
trans.da_DK = SoObjects/Mailer/Danish.lproj/Localizable.strings
|
||||
trans.de = SoObjects/Mailer/German.lproj/Localizable.strings
|
||||
trans.es_AR = SoObjects/Mailer/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = SoObjects/Mailer/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = SoObjects/Mailer/Basque.lproj/Localizable.strings
|
||||
trans.fi = SoObjects/Mailer/Finnish.lproj/Localizable.strings
|
||||
trans.fr = SoObjects/Mailer/French.lproj/Localizable.strings
|
||||
trans.hu = SoObjects/Mailer/Hungarian.lproj/Localizable.strings
|
||||
trans.is = SoObjects/Mailer/Icelandic.lproj/Localizable.strings
|
||||
trans.it = SoObjects/Mailer/Italian.lproj/Localizable.strings
|
||||
trans.nb_NO = SoObjects/Mailer/NorwegianBokmal.lproj/Localizable.strings
|
||||
trans.nl = SoObjects/Mailer/Dutch.lproj/Localizable.strings
|
||||
trans.nn_NO = SoObjects/Mailer/NorwegianNynorsk.lproj/Localizable.strings
|
||||
trans.pl = SoObjects/Mailer/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = SoObjects/Mailer/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = SoObjects/Mailer/Russian.lproj/Localizable.strings
|
||||
trans.sk = SoObjects/Mailer/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = SoObjects/Mailer/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = SoObjects/Mailer/Swedish.lproj/Localizable.strings
|
||||
trans.uk = SoObjects/Mailer/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = SoObjects/Mailer/ChineseTaiwan.lproj/Localizable.strings
|
||||
|
||||
[sogo.ui-mailpartviewers]
|
||||
source_file = UI/MailPartViewers/English.lproj/Localizable.strings
|
||||
@@ -302,7 +246,6 @@ trans.da_DK = UI/MailPartViewers/Danish.lproj/Localizable.strings
|
||||
trans.de = UI/MailPartViewers/German.lproj/Localizable.strings
|
||||
trans.es_AR = UI/MailPartViewers/SpanishArgentina.lproj/Localizable.strings
|
||||
trans.es_ES = UI/MailPartViewers/SpanishSpain.lproj/Localizable.strings
|
||||
trans.eu = UI/MailPartViewers/Basque.lproj/Localizable.strings
|
||||
trans.fi = UI/MailPartViewers/Finnish.lproj/Localizable.strings
|
||||
trans.fr = UI/MailPartViewers/French.lproj/Localizable.strings
|
||||
trans.hu = UI/MailPartViewers/Hungarian.lproj/Localizable.strings
|
||||
@@ -315,7 +258,5 @@ trans.pl = UI/MailPartViewers/Polish.lproj/Localizable.strings
|
||||
trans.pt_BR = UI/MailPartViewers/BrazilianPortuguese.lproj/Localizable.strings
|
||||
trans.ru = UI/MailPartViewers/Russian.lproj/Localizable.strings
|
||||
trans.sk = UI/MailPartViewers/Slovak.lproj/Localizable.strings
|
||||
trans.sl_SI = UI/MailPartViewers/Slovenian.lproj/Localizable.strings
|
||||
trans.sv = UI/MailPartViewers/Swedish.lproj/Localizable.strings
|
||||
trans.uk = UI/MailPartViewers/Ukrainian.lproj/Localizable.strings
|
||||
trans.zh_TW = UI/MailPartViewers/ChineseTaiwan.lproj/Localizable.strings
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@interface ActiveSyncProduct : NSObject
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation ActiveSyncProduct
|
||||
@end /* ActiveSyncProduct */
|
||||
@@ -1,42 +0,0 @@
|
||||
|
||||
# GNUstep makefile
|
||||
|
||||
include common.make
|
||||
|
||||
BUNDLE_NAME = ActiveSync
|
||||
|
||||
ActiveSync_PRINCIPAL_CLASS = ActiveSyncProduct
|
||||
|
||||
ActiveSync_OBJC_FILES = \
|
||||
ActiveSyncProduct.m \
|
||||
iCalAlarm+ActiveSync.m \
|
||||
iCalEvent+ActiveSync.m \
|
||||
iCalRecurrenceRule+ActiveSync.m \
|
||||
iCalTimeZone+ActiveSync.m \
|
||||
iCalToDo+ActiveSync.m \
|
||||
NSCalendarDate+ActiveSync.m \
|
||||
NSData+ActiveSync.m \
|
||||
NSDate+ActiveSync.m \
|
||||
NGDOMElement+ActiveSync.m \
|
||||
NGMimeMessage+ActiveSync.m \
|
||||
NGVCard+ActiveSync.m \
|
||||
NSArray+SyncCache.m \
|
||||
NSString+ActiveSync.m \
|
||||
SOGoActiveSyncDispatcher.m \
|
||||
SOGoActiveSyncDispatcher+Sync.m \
|
||||
SOGoMailObject+ActiveSync.m \
|
||||
SOGoSyncCacheObject.m \
|
||||
SoObjectWebDAVDispatcher+ActiveSync.m
|
||||
|
||||
ActiveSync_RESOURCE_FILES += \
|
||||
product.plist
|
||||
|
||||
ADDITIONAL_OBJCFLAGS += -Wno-deprecated-declarations
|
||||
ADDITIONAL_INCLUDE_DIRS += -I../SOPE/ -I../SoObjects/
|
||||
ADDITIONAL_LIB_DIRS += -L../SOPE/GDLContentStore/obj/ -L../SOPE/NGCards/obj/
|
||||
ADDITIONAL_INCLUDE_DIRS += -I/usr/include/libwbxml-1.0/
|
||||
ADDITIONAL_LDFLAGS += -Wl,--no-as-needed -lwbxml2
|
||||
|
||||
-include GNUmakefile.preamble
|
||||
include $(GNUSTEP_MAKEFILES)/bundle.make
|
||||
-include GNUmakefile.postamble
|
||||
@@ -1 +0,0 @@
|
||||
# compilation settings
|
||||
@@ -1,25 +0,0 @@
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __NGDOMELEMENTACTIVESYNC_H__
|
||||
#define __NGDOMELEMENTACTIVESYNC_H__
|
||||
|
||||
#import <DOM/DOMElement.h>
|
||||
#import <DOM/DOMProtocols.h>
|
||||
|
||||
@class NSDictionary;
|
||||
|
||||
@interface NGDOMElement (ActiveSync)
|
||||
|
||||
- (NSDictionary *) applicationData;
|
||||
|
||||
@end
|
||||
|
||||
#endif // NGDOMELEMENTACTIVESYNC
|
||||
@@ -1,190 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#include "NGDOMElement+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
static NSArray *asElementArray = nil;
|
||||
|
||||
@implementation NGDOMElement (ActiveSync)
|
||||
|
||||
- (BOOL) isTextNode
|
||||
{
|
||||
id <DOMNodeList> children;
|
||||
id <DOMElement> element;
|
||||
int i;
|
||||
|
||||
if ([self nodeType] == DOM_TEXT_NODE)
|
||||
return YES;
|
||||
|
||||
children = [self childNodes];
|
||||
|
||||
for (i = 0; i < [children length]; i++)
|
||||
{
|
||||
element = [children objectAtIndex: i];
|
||||
|
||||
if ([element nodeType] != DOM_TEXT_NODE)
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
//
|
||||
// We must handle "inner data" like this:
|
||||
//
|
||||
// <ApplicationData>
|
||||
// <Flag xmlns="Email:">
|
||||
// <FlagStatus>2</FlagStatus>
|
||||
// <FlagType>Flag for follow up</FlagType>
|
||||
// </Flag>
|
||||
// </ApplicationData>
|
||||
//
|
||||
// and stuff like that:
|
||||
//
|
||||
// <Attendees xmlns="Calendar:">
|
||||
// <Attendee>
|
||||
// <Attendee_Email>sogo1@example.com</Attendee_Email>
|
||||
// <Attendee_Name>John Doe</Attendee_Name>
|
||||
// <Attendee_Status>5</Attendee_Status>
|
||||
// <Attendee_Type>1</Attendee_Type>
|
||||
// </Attendee>
|
||||
// <Attendee>
|
||||
// <Attendee_Email>sogo2@example.com</Attendee_Email>
|
||||
// <Attendee_Name>Balthazar César</Attendee_Name>
|
||||
// <Attendee_Status>5</Attendee_Status>
|
||||
// <Attendee_Type>1</Attendee_Type>
|
||||
// </Attendee>
|
||||
// <Attendee>
|
||||
// <Attendee_Email>sogo3@example.com</Attendee_Email>
|
||||
// <Attendee_Name>Wolfgang Fritz</Attendee_Name>
|
||||
// <Attendee_Status>5</Attendee_Status>
|
||||
// <Attendee_Type>1</Attendee_Type>
|
||||
// </Attendee>
|
||||
// </Attendees>
|
||||
//
|
||||
|
||||
- (NSDictionary *) applicationData
|
||||
{
|
||||
NSMutableDictionary *data;
|
||||
id <DOMNodeList> children;
|
||||
id <DOMElement> element;
|
||||
int i, count;
|
||||
|
||||
if (!asElementArray)
|
||||
asElementArray = [[NSArray alloc] initWithObjects: @"Attendee", @"Category", nil];
|
||||
|
||||
data = [NSMutableDictionary dictionary];
|
||||
|
||||
children = [self childNodes];
|
||||
|
||||
for (i = 0; i < [children length]; i++)
|
||||
{
|
||||
element = [children objectAtIndex: i];
|
||||
|
||||
if ([element nodeType] == DOM_ELEMENT_NODE)
|
||||
{
|
||||
NSString *tag;
|
||||
id value;
|
||||
|
||||
tag = [element tagName];
|
||||
count = [(NSArray *)[element childNodes] count];
|
||||
|
||||
// We check if the node is a text one or if all its
|
||||
// children are text nodes. This is important to avoid side-effects
|
||||
// in SOPE where "foo & bar" would result into 3 childnodes instead
|
||||
// of just one.
|
||||
if ([(id)element isTextNode])
|
||||
{
|
||||
value = [(id)element textValue];
|
||||
}
|
||||
// Handle inner data - see above for samples
|
||||
else
|
||||
{
|
||||
NSMutableArray *innerElements;
|
||||
id <DOMElement> innerElement;
|
||||
NSArray *childNodes;
|
||||
NSString *innerTag;
|
||||
BOOL same;
|
||||
int j;
|
||||
|
||||
childNodes = (NSArray *)[element childNodes];
|
||||
innerElements = [NSMutableArray array];
|
||||
innerTag = nil;
|
||||
same = YES;
|
||||
|
||||
for (j = 1; j < count; j++)
|
||||
{
|
||||
innerElement = [childNodes objectAtIndex: j];
|
||||
|
||||
if ([innerElement nodeType] == DOM_ELEMENT_NODE)
|
||||
{
|
||||
if (!innerTag)
|
||||
innerTag = [innerElement tagName];
|
||||
|
||||
if ([innerTag isEqualToString: [innerElement tagName]])
|
||||
{
|
||||
if ([(id)innerElement isTextNode])
|
||||
[innerElements addObject: [(NGDOMElement *)innerElement textValue]];
|
||||
else
|
||||
[innerElements addObject: [(NGDOMElement *)innerElement applicationData]];
|
||||
}
|
||||
else
|
||||
{
|
||||
same = NO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (same && [asElementArray containsObject: innerTag])
|
||||
value = innerElements;
|
||||
else
|
||||
{
|
||||
value = [(NGDOMElement *)element applicationData];
|
||||
|
||||
// Don't set empty values like Foo = {}
|
||||
if (![value count])
|
||||
value = nil;
|
||||
}
|
||||
}
|
||||
|
||||
if (value && tag)
|
||||
[data setObject: value forKey: tag];
|
||||
|
||||
} // if ([element nodeType] == DOM_ELEMENT_NODE)
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __NGMIMEMESSAGEACTIVESYNC_H__
|
||||
#define __NGMIMEMESSAGEACTIVESYNC_H__
|
||||
|
||||
#import <NGMail/NGMimeMessage.h>
|
||||
|
||||
@class NSArray;
|
||||
|
||||
@interface NGMimeMessage (ActiveSync)
|
||||
|
||||
- (NSArray *) allRecipients;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2015, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#import "NGMimeMessage+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGMail/NGMailAddress.h>
|
||||
#import <NGMail/NGMailAddressParser.h>
|
||||
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
|
||||
@implementation NGMimeMessage (ActiveSync)
|
||||
|
||||
- (void) _addRecipients: (NSEnumerator *) enumerator
|
||||
toArray: (NSMutableArray *) recipients
|
||||
{
|
||||
NGMailAddressParser *parser;
|
||||
NSEnumerator *addressList;
|
||||
NGMailAddress *address;
|
||||
NSString *s;
|
||||
|
||||
while ((s = [enumerator nextObject]))
|
||||
{
|
||||
parser = [NGMailAddressParser mailAddressParserWithString: s];
|
||||
addressList = [[parser parseAddressList] objectEnumerator];
|
||||
|
||||
while ((address = [addressList nextObject]))
|
||||
[recipients addObject: [address address]];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *) allRecipients
|
||||
{
|
||||
NSMutableArray *recipients;
|
||||
|
||||
recipients = [NSMutableArray array];
|
||||
|
||||
[self _addRecipients: [[self headersForKey: @"to"] objectEnumerator]
|
||||
toArray: recipients];
|
||||
|
||||
[self _addRecipients: [[self headersForKey: @"cc"] objectEnumerator]
|
||||
toArray: recipients];
|
||||
|
||||
[self _addRecipients: [[self headersForKey: @"bcc"] objectEnumerator]
|
||||
toArray: recipients];
|
||||
|
||||
return recipients;
|
||||
}
|
||||
@end
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __NGVCARDACTIVESYNC_H__
|
||||
#define __NGVCARDACTIVESYNC_H__
|
||||
|
||||
#import <NGCards/NGVCard.h>
|
||||
|
||||
@class NSDictionary;
|
||||
@class NSString;
|
||||
@class WOContext;
|
||||
|
||||
@interface NGVCard (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,362 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#import "NGVCard+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
|
||||
#import <NGCards/CardElement.h>
|
||||
|
||||
#import <Contacts/NGVCard+SOGo.h>
|
||||
|
||||
#import <SOGo/NSString+Utilities.h>
|
||||
|
||||
#include "NSDate+ActiveSync.h"
|
||||
#include "NSString+ActiveSync.h"
|
||||
|
||||
@implementation NGVCard (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSArray *emails, *addresses, *categories, *elements;
|
||||
CardElement *n, *homeAdr, *workAdr;
|
||||
NSMutableString *s;
|
||||
NSString *url;
|
||||
id o;
|
||||
|
||||
int i;
|
||||
|
||||
s = [NSMutableString string];
|
||||
n = [self n];
|
||||
|
||||
if ((o = [n flattenedValueAtIndex: 0 forKey: @""]))
|
||||
[s appendFormat: @"<LastName xmlns=\"Contacts:\">%@</LastName>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [n flattenedValueAtIndex: 1 forKey: @""]))
|
||||
[s appendFormat: @"<FirstName xmlns=\"Contacts:\">%@</FirstName>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [self workCompany]))
|
||||
[s appendFormat: @"<CompanyName xmlns=\"Contacts:\">%@</CompanyName>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [[self org] flattenedValueAtIndex: 1 forKey: @""]))
|
||||
[s appendFormat: @"<Department xmlns=\"Contacts:\">%@</Department>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
categories = [self categories];
|
||||
|
||||
if ([categories count])
|
||||
{
|
||||
[s appendFormat: @"<Categories xmlns=\"Contacts:\">"];
|
||||
for (i = 0; i < [categories count]; i++)
|
||||
{
|
||||
[s appendFormat: @"<Category xmlns=\"Contacts:\">%@</Category>", [[categories objectAtIndex: i] activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
[s appendFormat: @"</Categories>"];
|
||||
}
|
||||
|
||||
elements = [self childrenWithTag: @"url"
|
||||
andAttribute: @"type"
|
||||
havingValue: @"work"];
|
||||
if ([elements count] > 0)
|
||||
{
|
||||
url = [[elements objectAtIndex: 0] flattenedValuesForKey: @""];
|
||||
[s appendFormat: @"<WebPage xmlns=\"Contacts:\">%@</WebPage>", [url activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
|
||||
if ((o = [[self uniqueChildWithTag: @"x-aim"] flattenedValuesForKey: @""]))
|
||||
[s appendFormat: @"<IMAddress xmlns=\"Contacts:\">%@</IMAddress>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [self nickname]))
|
||||
[s appendFormat: @"<NickName xmlns=\"Contacts:\">%@</NickName>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
|
||||
if ((o = [self title]))
|
||||
[s appendFormat: @"<JobTitle xmlns=\"Contacts:\">%@</JobTitle>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [self preferredEMail]))
|
||||
[s appendFormat: @"<Email1Address xmlns=\"Contacts:\">%@</Email1Address>", o];
|
||||
|
||||
|
||||
// Secondary email addresses (2 and 3)
|
||||
emails = [self secondaryEmails];
|
||||
|
||||
for (i = 0; i < [emails count]; i++)
|
||||
{
|
||||
o = [[emails objectAtIndex: i] flattenedValuesForKey: @""];
|
||||
|
||||
[s appendFormat: @"<Email%dAddress xmlns=\"Contacts:\">%@</Email%dAddress>", i+2, o, i+2];
|
||||
|
||||
if (i == 1)
|
||||
break;
|
||||
}
|
||||
|
||||
// Telephone numbers
|
||||
if ((o = [self workPhone]) && [o length])
|
||||
[s appendFormat: @"<BusinessPhoneNumber xmlns=\"Contacts:\">%@</BusinessPhoneNumber>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [self homePhone]) && [o length])
|
||||
[s appendFormat: @"<HomePhoneNumber xmlns=\"Contacts:\">%@</HomePhoneNumber>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [self fax]) && [o length])
|
||||
[s appendFormat: @"<BusinessFaxNumber xmlns=\"Contacts:\">%@</BusinessFaxNumber>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [self mobile]) && [o length])
|
||||
[s appendFormat: @"<MobilePhoneNumber xmlns=\"Contacts:\">%@</MobilePhoneNumber>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [self pager]) && [o length])
|
||||
[s appendFormat: @"<PagerNumber xmlns=\"Contacts:\">%@</PagerNumber>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Home Address
|
||||
addresses = [self childrenWithTag: @"adr"
|
||||
andAttribute: @"type"
|
||||
havingValue: @"home"];
|
||||
|
||||
if ([addresses count])
|
||||
{
|
||||
homeAdr = [addresses objectAtIndex: 0];
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 2 forKey: @""]))
|
||||
[s appendFormat: @"<HomeStreet xmlns=\"Contacts:\">%@</HomeStreet>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 3 forKey: @""]))
|
||||
[s appendFormat: @"<HomeCity xmlns=\"Contacts:\">%@</HomeCity>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 4 forKey: @""]))
|
||||
[s appendFormat: @"<HomeState xmlns=\"Contacts:\">%@</HomeState>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 5 forKey: @""]))
|
||||
[s appendFormat: @"<HomePostalCode xmlns=\"Contacts:\">%@</HomePostalCode>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [homeAdr flattenedValueAtIndex: 6 forKey: @""]))
|
||||
[s appendFormat: @"<HomeCountry xmlns=\"Contacts:\">%@</HomeCountry>", [o activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
// Work Address
|
||||
addresses = [self childrenWithTag: @"adr"
|
||||
andAttribute: @"type"
|
||||
havingValue: @"work"];
|
||||
|
||||
if ([addresses count])
|
||||
{
|
||||
workAdr = [addresses objectAtIndex: 0];
|
||||
|
||||
if ((o = [workAdr flattenedValueAtIndex: 2 forKey: @""]))
|
||||
[s appendFormat: @"<BusinessStreet xmlns=\"Contacts:\">%@</BusinessStreet>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [workAdr flattenedValueAtIndex: 3 forKey: @""]))
|
||||
[s appendFormat: @"<BusinessCity xmlns=\"Contacts:\">%@</BusinessCity>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [workAdr flattenedValueAtIndex: 4 forKey: @""]))
|
||||
[s appendFormat: @"<BusinessState xmlns=\"Contacts:\">%@</BusinessState>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [workAdr flattenedValueAtIndex: 5 forKey: @""]))
|
||||
[s appendFormat: @"<BusinessPostalCode xmlns=\"Contacts:\">%@</BusinessPostalCode>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [workAdr flattenedValueAtIndex: 6 forKey: @""]))
|
||||
[s appendFormat: @"<BusinessCountry xmlns=\"Contacts:\">%@</BusinessCountry>", [o activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
// Other, less important fields
|
||||
if ((o = [self birthday]))
|
||||
[s appendFormat: @"<Birthday xmlns=\"Contacts:\">%@</Birthday>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [self note]))
|
||||
{
|
||||
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
|
||||
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
|
||||
o = [o activeSyncRepresentationInContext: context];
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
[s appendFormat: @"<Type>%d</Type>", 1];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
|
||||
[s appendFormat: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
|
||||
if ((o = [self photo]))
|
||||
[s appendFormat: @"<Picture xmlns=\"Contacts:\">%@</Picture>", o];
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
CardElement *element;
|
||||
id o;
|
||||
|
||||
// Contact's note
|
||||
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
||||
[self setNote: o];
|
||||
|
||||
// Categories
|
||||
if ((o = [theValues objectForKey: @"Categories"]) && [o length])
|
||||
[self setCategories: o];
|
||||
|
||||
// Birthday
|
||||
if ((o = [theValues objectForKey: @"Birthday"]))
|
||||
{
|
||||
o = [o calendarDate];
|
||||
[self setBday: [o descriptionWithCalendarFormat: @"%Y-%m-%d" timeZone: nil locale: nil]];
|
||||
}
|
||||
|
||||
//
|
||||
// Business address information
|
||||
//
|
||||
// BusinessStreet
|
||||
// BusinessCity
|
||||
// BusinessPostalCode
|
||||
// BusinessState
|
||||
// BusinessCountry
|
||||
//
|
||||
element = [self elementWithTag: @"adr" ofType: @"work"];
|
||||
[element setSingleValue: @""
|
||||
atIndex: 1 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessStreet"]
|
||||
atIndex: 2 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessCity"]
|
||||
atIndex: 3 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessState"]
|
||||
atIndex: 4 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessPostalCode"]
|
||||
atIndex: 5 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessCountry"]
|
||||
atIndex: 6 forKey: @""];
|
||||
|
||||
//
|
||||
// Home address information
|
||||
//
|
||||
// HomeStreet
|
||||
// HomeCity
|
||||
// HomePostalCode
|
||||
// HomeState
|
||||
// HomeCountry
|
||||
//
|
||||
element = [self elementWithTag: @"adr" ofType: @"home"];
|
||||
[element setSingleValue: @""
|
||||
atIndex: 1 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeStreet"]
|
||||
atIndex: 2 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeCity"]
|
||||
atIndex: 3 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeState"]
|
||||
atIndex: 4 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomePostalCode"]
|
||||
atIndex: 5 forKey: @""];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomeCountry"]
|
||||
atIndex: 6 forKey: @""];
|
||||
|
||||
// Company's name
|
||||
if ((o = [theValues objectForKey: @"CompanyName"]))
|
||||
[self setOrg: o units: nil];
|
||||
|
||||
// Department
|
||||
if ((o = [theValues objectForKey: @"Department"]))
|
||||
[self setOrg: nil units: [NSArray arrayWithObjects:o,nil]];
|
||||
|
||||
// Email addresses
|
||||
if ((o = [theValues objectForKey: @"Email1Address"]))
|
||||
{
|
||||
element = [self elementWithTag: @"email" ofType: @"work"];
|
||||
[element setSingleValue: [o pureEMailAddress] forKey: @""];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"Email2Address"]))
|
||||
{
|
||||
element = [self elementWithTag: @"email" ofType: @"home"];
|
||||
[element setSingleValue: [o pureEMailAddress] forKey: @""];
|
||||
}
|
||||
|
||||
// SOGo currently only supports 2 email addresses ... but AS clients might send 3
|
||||
// FIXME: revise this when the GUI revamp is done in SOGo
|
||||
if ((o = [theValues objectForKey: @"Email3Address"]))
|
||||
{
|
||||
element = [self elementWithTag: @"email" ofType: @"three"];
|
||||
[element setSingleValue: [o pureEMailAddress] forKey: @""];
|
||||
}
|
||||
|
||||
// Formatted name
|
||||
// MiddleName
|
||||
// Suffix (II)
|
||||
// Title (Mr.)
|
||||
[self setFn: [theValues objectForKey: @"FileAs"]];
|
||||
|
||||
[self setNWithFamily: [theValues objectForKey: @"LastName"]
|
||||
given: [theValues objectForKey: @"FirstName"]
|
||||
additional: nil prefixes: nil suffixes: nil];
|
||||
|
||||
// IM information
|
||||
[[self uniqueChildWithTag: @"x-aim"]
|
||||
setSingleValue: [theValues objectForKey: @"IMAddress"]
|
||||
forKey: @""];
|
||||
|
||||
//
|
||||
// Phone numbrrs
|
||||
//
|
||||
element = [self elementWithTag: @"tel" ofType: @"work"];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessPhoneNumber"] forKey: @""];
|
||||
|
||||
element = [self elementWithTag: @"tel" ofType: @"home"];
|
||||
[element setSingleValue: [theValues objectForKey: @"HomePhoneNumber"] forKey: @""];
|
||||
|
||||
element = [self elementWithTag: @"tel" ofType: @"cell"];
|
||||
[element setSingleValue: [theValues objectForKey: @"MobilePhoneNumber"] forKey: @""];
|
||||
|
||||
element = [self elementWithTag: @"tel" ofType: @"fax"];
|
||||
[element setSingleValue: [theValues objectForKey: @"BusinessFaxNumber"] forKey: @""];
|
||||
|
||||
element = [self elementWithTag: @"tel" ofType: @"pager"];
|
||||
[element setSingleValue: [theValues objectForKey: @"PagerNumber"] forKey: @""];
|
||||
|
||||
// Job's title
|
||||
if ((o = [theValues objectForKey: @"JobTitle"]))
|
||||
[self setTitle: o];
|
||||
|
||||
// WebPage (work)
|
||||
if ((o = [theValues objectForKey: @"WebPage"]))
|
||||
[[self elementWithTag: @"url" ofType: @"work"]
|
||||
setSingleValue: o forKey: @""];
|
||||
|
||||
if ((o = [theValues objectForKey: @"NickName"]))
|
||||
[self setNickname: o];
|
||||
|
||||
if ((o = [theValues objectForKey: @"Picture"]))
|
||||
[self setPhoto: o];
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __NSARRAYSYNCCACHE_H__
|
||||
#define __NSARRAYSYNCCACHE_H__
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
|
||||
@class NSDictionary;
|
||||
|
||||
@interface NSMutableArray (SyncCache)
|
||||
|
||||
- (id) initWithDictionary: (NSDictionary *) theDictionary;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSArray (SyncCache)
|
||||
|
||||
- (NSDictionary *) dictionaryValue;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#import "NSArray+SyncCache.h"
|
||||
|
||||
#import <Foundation/NSDictionary.h>
|
||||
|
||||
#include "SOGoSyncCacheObject.h"
|
||||
|
||||
@implementation NSMutableArray (SyncCache)
|
||||
|
||||
- (id) initWithDictionary: (NSDictionary *) theDictionary
|
||||
{
|
||||
SOGoSyncCacheObject *o;
|
||||
NSArray *allKeys;
|
||||
id key;
|
||||
int i;
|
||||
|
||||
self = [self initWithCapacity: [theDictionary count]];
|
||||
|
||||
allKeys = [theDictionary allKeys];
|
||||
|
||||
for (i = 0; i < [allKeys count]; i++)
|
||||
{
|
||||
key = [allKeys objectAtIndex: i];
|
||||
o = [SOGoSyncCacheObject syncCacheObjectWithUID: key
|
||||
sequence: [theDictionary objectForKey: key]];
|
||||
[self addObject: o];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
@implementation NSArray (SyncCache)
|
||||
|
||||
- (NSDictionary *) dictionaryValue
|
||||
{
|
||||
NSMutableDictionary *d;
|
||||
SOGoSyncCacheObject *o;
|
||||
int i;
|
||||
|
||||
d = [NSMutableDictionary dictionary];
|
||||
|
||||
for (i = 0; i < [self count]; i++)
|
||||
{
|
||||
o = [self objectAtIndex: i];
|
||||
[d setObject: [o sequence] forKey: [o uid]];
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __NSCALENDARDATEACTIVESYNC_H__
|
||||
#define __NSCALENDARDATEACTIVESYNC_H__
|
||||
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
|
||||
@class NSString;
|
||||
|
||||
@interface NSCalendarDate (ActiveSync)
|
||||
|
||||
+ (NSCalendarDate *) dateFromFilterType: (NSString *) theFilterType;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#import "NSCalendarDate+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#define ONE_DAY 86400
|
||||
|
||||
@implementation NSCalendarDate (ActiveSync)
|
||||
|
||||
//
|
||||
// See http://msdn.microsoft.com/en-us/library/gg709713(v=exchg.80).aspx for available types
|
||||
//
|
||||
+ (NSCalendarDate *) dateFromFilterType: (NSString *) theFilterType
|
||||
{
|
||||
NSCalendarDate *d;
|
||||
|
||||
d = [NSCalendarDate calendarDate];
|
||||
|
||||
if (d)
|
||||
{
|
||||
int value;
|
||||
|
||||
switch ([theFilterType intValue])
|
||||
{
|
||||
case 1:
|
||||
value = ONE_DAY;
|
||||
break;
|
||||
case 2:
|
||||
value = 3 * ONE_DAY;
|
||||
break;
|
||||
case 3:
|
||||
value = 7 * ONE_DAY;
|
||||
break;
|
||||
case 4:
|
||||
value = 14 * ONE_DAY;
|
||||
break;
|
||||
case 5:
|
||||
value = 30 * ONE_DAY;
|
||||
break;
|
||||
case 6:
|
||||
value = 90 * ONE_DAY;
|
||||
break;
|
||||
case 7:
|
||||
value = 180 * ONE_DAY;
|
||||
break;
|
||||
case 0:
|
||||
case 8:
|
||||
default:
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [d initWithTimeIntervalSinceNow: -value];
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __NSDATAACTIVESYNC_H__
|
||||
#define __NSDATAACTIVESYNC_H__
|
||||
|
||||
#import <Foundation/NSData.h>
|
||||
|
||||
@class NSString;
|
||||
@class WOContext;
|
||||
|
||||
@interface NSData (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
|
||||
- (NSData *) wbxml2xml;
|
||||
- (NSData *) xml2wbxml;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,185 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#import "NSData+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSProcessInfo.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <SOGo/SOGoSystemDefaults.h>
|
||||
|
||||
#import <NGExtensions/NGBase64Coding.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#include <wbxml/wbxml.h>
|
||||
#include <wbxml/wbxml_conv.h>
|
||||
#include <wbxml/wbxml_errors.h>
|
||||
|
||||
#define WBXMLDEBUG 0
|
||||
|
||||
@implementation NSData (ActiveSync)
|
||||
|
||||
- (void) _dumpToFile
|
||||
{
|
||||
BOOL debugOn;
|
||||
|
||||
debugOn = [[SOGoSystemDefaults sharedSystemDefaults] easDebugEnabled];
|
||||
|
||||
if (debugOn)
|
||||
{
|
||||
NSString *path;
|
||||
|
||||
path = [NSString stringWithFormat: @"/tmp/%@.data", [[NSProcessInfo processInfo] globallyUniqueString]];
|
||||
[self writeToFile: path atomically: YES];
|
||||
[self errorWithFormat: @"Original data written to: %@", path];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Encodes the data in base64 and strip newline characters
|
||||
//
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSString *tmp, *s;
|
||||
unichar *buf, *start, c;
|
||||
int len, i, j;
|
||||
|
||||
tmp = [self stringByEncodingBase64] ;
|
||||
|
||||
len = [tmp length];
|
||||
|
||||
start = buf = (unichar *)malloc(len*sizeof(unichar));
|
||||
[tmp getCharacters: buf range: NSMakeRange(0, len)];
|
||||
|
||||
for (i = 0, j = 0; i < len; i++)
|
||||
{
|
||||
c = *buf;
|
||||
|
||||
if (!(c == 0xA))
|
||||
{
|
||||
*(start+j) = c;
|
||||
j++;
|
||||
}
|
||||
|
||||
buf++;
|
||||
}
|
||||
|
||||
s = [[NSString alloc] initWithCharactersNoCopy: start length: j freeWhenDone: YES];
|
||||
|
||||
return AUTORELEASE(s);
|
||||
}
|
||||
|
||||
- (NSData *) wbxml2xml
|
||||
{
|
||||
WBXMLGenXMLParams params;
|
||||
NSData *data;
|
||||
|
||||
unsigned int wbxml_len, xml_len, ret;
|
||||
unsigned char *wbxml, *xml;
|
||||
|
||||
wbxml = (unsigned char*)[self bytes];
|
||||
wbxml_len = [self length];
|
||||
xml = NULL;
|
||||
xml_len = 0;
|
||||
|
||||
params.lang = WBXML_LANG_ACTIVESYNC;
|
||||
params.gen_type = WBXML_GEN_XML_INDENT;
|
||||
params.indent = 1;
|
||||
params.keep_ignorable_ws = FALSE;
|
||||
|
||||
ret = wbxml_conv_wbxml2xml_withlen(wbxml, wbxml_len, &xml, &xml_len, ¶ms);
|
||||
|
||||
if (ret != WBXML_OK)
|
||||
{
|
||||
[self errorWithFormat: @"wbxml2xmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
|
||||
[self _dumpToFile];
|
||||
return nil;
|
||||
}
|
||||
|
||||
data = [NSData dataWithBytesNoCopy: xml length: xml_len freeWhenDone: YES];
|
||||
|
||||
#if WBXMLDEBUG
|
||||
[data writeToFile: @"/tmp/protocol.decoded" atomically: YES];
|
||||
#endif
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
- (NSData *) xml2wbxml
|
||||
{
|
||||
WBXMLConvXML2WBXML *conv;
|
||||
NSData *data;
|
||||
|
||||
unsigned int wbxml_len, xml_len, ret;
|
||||
unsigned char *wbxml, *xml;
|
||||
|
||||
xml = (unsigned char*)[self bytes];
|
||||
xml_len = [self length];
|
||||
wbxml = NULL;
|
||||
wbxml_len = 0;
|
||||
conv = NULL;
|
||||
|
||||
ret = wbxml_conv_xml2wbxml_create(&conv);
|
||||
|
||||
if (ret != WBXML_OK)
|
||||
{
|
||||
[self logWithFormat: @"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
|
||||
[self _dumpToFile];
|
||||
return nil;
|
||||
}
|
||||
|
||||
wbxml_conv_xml2wbxml_enable_preserve_whitespaces(conv);
|
||||
|
||||
// From libwbxml's changelog in v0.11.0: "The public ID is set to unknown and the DTD is not included. This is required for Microsoft ActiveSync."
|
||||
wbxml_conv_xml2wbxml_disable_public_id(conv);
|
||||
wbxml_conv_xml2wbxml_disable_string_table(conv);
|
||||
|
||||
ret = wbxml_conv_xml2wbxml_run(conv, xml, xml_len, &wbxml, &wbxml_len);
|
||||
|
||||
if (ret != WBXML_OK)
|
||||
{
|
||||
[self errorWithFormat: @"xml2wbxmlFromContent: failed: %s\n", wbxml_errors_string(ret)];
|
||||
[self _dumpToFile];
|
||||
free(wbxml);
|
||||
wbxml_conv_xml2wbxml_destroy(conv);
|
||||
return nil;
|
||||
}
|
||||
|
||||
data = [NSData dataWithBytesNoCopy: wbxml length: wbxml_len freeWhenDone: YES];
|
||||
|
||||
#if WBXMLDEBUG
|
||||
[data writeToFile: @"/tmp/protocol.encoded" atomically: YES];
|
||||
#endif
|
||||
|
||||
wbxml_conv_xml2wbxml_destroy(conv);
|
||||
|
||||
return data;
|
||||
}
|
||||
@end
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __NSDATEACTIVESYNC_H__
|
||||
#define __NSDATEACTIVESYNC_H__
|
||||
|
||||
#import <Foundation/NSDate.h>
|
||||
|
||||
@class NSString;
|
||||
@class WOContext;
|
||||
|
||||
@interface NSDate (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
|
||||
- (NSString *) activeSyncRepresentationWithoutSeparatorsInContext: (WOContext *) context;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#import "NSDate+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
@implementation NSDate (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
return [self descriptionWithCalendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ" timeZone: [NSTimeZone timeZoneWithName: @"GMT"] locale: nil];
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// From [MS-ASDTYPE].pdf - section 2.3 "Dates and times in calendar items MUST NOT include punctuation separators."
|
||||
//
|
||||
- (NSString *) activeSyncRepresentationWithoutSeparatorsInContext: (WOContext *) context
|
||||
{
|
||||
return [self descriptionWithCalendarFormat: @"%Y%m%dT%H%M%SZ" timeZone: [NSTimeZone timeZoneWithName: @"GMT"] locale: nil];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014-2015, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __NSSTRINGACTIVESYNC_H__
|
||||
#define __NSSTRINGACTIVESYNC_H__
|
||||
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#include "SOGoActiveSyncConstants.h"
|
||||
|
||||
@class NSCalendarDate;
|
||||
@class NSData;
|
||||
@class WOContext;
|
||||
|
||||
@interface NSString (ActiveSync)
|
||||
|
||||
- (NSString *) sanitizedServerIdWithType: (SOGoMicrosoftActiveSyncFolderType) folderType;
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
|
||||
- (int) activeSyncFolderType;
|
||||
- (NSString *) realCollectionIdWithFolderType: (SOGoMicrosoftActiveSyncFolderType *) folderType;
|
||||
- (NSCalendarDate *) calendarDate;
|
||||
- (NSString *) deviceId;
|
||||
- (NSString *) deviceType;
|
||||
- (NSString *) attachmentName;
|
||||
- (NSString *) command;
|
||||
- (NSString *) collectionid;
|
||||
- (NSString *) itemid;
|
||||
- (BOOL) acceptsMultiPart;
|
||||
- (NSData *) convertHexStringToBytes;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,523 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#include "NSString+ActiveSync.h"
|
||||
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <Foundation/NSCalendarDate.h>
|
||||
#include <Foundation/NSData.h>
|
||||
#include <Foundation/NSDate.h>
|
||||
#include <Foundation/NSTimeZone.h>
|
||||
|
||||
#include <SOGo/NSString+Utilities.h>
|
||||
#include <SOGo/NSData+Crypto.h>
|
||||
|
||||
#include <NGExtensions/NGBase64Coding.h>
|
||||
#include <NGExtensions/NSString+misc.h>
|
||||
|
||||
static NSArray *easCommandCodes = nil;
|
||||
static NSArray *easCommandParameters = nil;
|
||||
|
||||
@implementation NSString (ActiveSync)
|
||||
|
||||
//
|
||||
// This is a copy from NSString+XMLEscaping.m from SOPE.
|
||||
// The difference here is that we use wchar_t instead of unichar.
|
||||
// This is needed to get the rigth numeric character reference.
|
||||
// e.g. SMILING FACE WITH OPEN MOUTH
|
||||
// ok: wchar_t -> 😃 wrong: unichar -> � �
|
||||
//
|
||||
// We avoir naming it like the one in SOPE since if the ActiveSync
|
||||
// bundle is loaded, it'll overwrite the one provided by SOPE.
|
||||
//
|
||||
- (NSString *) _stringByEscapingXMLStringUsingCharacters {
|
||||
register unsigned i, len, j;
|
||||
register wchar_t *buf;
|
||||
const wchar_t *chars;
|
||||
unsigned escapeCount;
|
||||
|
||||
if ([self length] == 0) return @"";
|
||||
|
||||
NSData *data = [self dataUsingEncoding:NSUTF32StringEncoding];
|
||||
chars = [data bytes];
|
||||
len = [data length]/4;
|
||||
|
||||
/* check for characters to escape ... */
|
||||
for (i = 0, escapeCount = 0; i < len; i++) {
|
||||
switch (chars[i]) {
|
||||
case '&': case '"': case '<': case '>': case '\r':
|
||||
escapeCount++;
|
||||
break;
|
||||
default:
|
||||
if (chars[i] > 127)
|
||||
escapeCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (escapeCount == 0 ) {
|
||||
/* nothing to escape ... */
|
||||
return [[self copy] autorelease];
|
||||
}
|
||||
|
||||
buf = calloc((len + 5) + (escapeCount * 16), sizeof(wchar_t));
|
||||
for (i = 0, j = 0; i < len; i++) {
|
||||
switch (chars[i]) {
|
||||
/* escape special chars */
|
||||
case '\r':
|
||||
buf[j] = '&'; j++; buf[j] = '#'; j++; buf[j] = '1'; j++;
|
||||
buf[j] = '3'; j++; buf[j] = ';'; j++;
|
||||
break;
|
||||
case '&':
|
||||
buf[j] = '&'; j++; buf[j] = 'a'; j++; buf[j] = 'm'; j++;
|
||||
buf[j] = 'p'; j++; buf[j] = ';'; j++;
|
||||
break;
|
||||
case '"':
|
||||
buf[j] = '&'; j++; buf[j] = 'q'; j++; buf[j] = 'u'; j++;
|
||||
buf[j] = 'o'; j++; buf[j] = 't'; j++; buf[j] = ';'; j++;
|
||||
break;
|
||||
case '<':
|
||||
buf[j] = '&'; j++; buf[j] = 'l'; j++; buf[j] = 't'; j++;
|
||||
buf[j] = ';'; j++;
|
||||
break;
|
||||
case '>':
|
||||
buf[j] = '&'; j++; buf[j] = 'g'; j++; buf[j] = 't'; j++;
|
||||
buf[j] = ';'; j++;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* escape big chars */
|
||||
if (chars[i] > 127) {
|
||||
unsigned char nbuf[32];
|
||||
unsigned int k;
|
||||
|
||||
sprintf((char *)nbuf, "&#%i;", (int)chars[i]);
|
||||
for (k = 0; nbuf[k] != '\0'; k++) {
|
||||
buf[j] = nbuf[k];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
else if (chars[i] == 0x9 || chars[i] == 0xA || chars[i] == 0xD || chars[i] >= 0x20) { // ignore any unsupported control character
|
||||
/* nothing to escape */
|
||||
buf[j] = chars[i];
|
||||
j++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self = [[NSString alloc] initWithBytesNoCopy: buf
|
||||
length: (j*sizeof(wchar_t))
|
||||
encoding: NSUTF32StringEncoding
|
||||
freeWhenDone: YES];
|
||||
|
||||
return [self autorelease];
|
||||
}
|
||||
|
||||
- (NSString *) sanitizedServerIdWithType: (SOGoMicrosoftActiveSyncFolderType) folderType
|
||||
{
|
||||
if (folderType == ActiveSyncEventFolder)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = [self length];
|
||||
|
||||
if (len > 4 && [self hasSuffix: @".ics"])
|
||||
return [self substringToIndex: len-4];
|
||||
else
|
||||
return [NSString stringWithFormat: @"%@.ics", self];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
return [self _stringByEscapingXMLStringUsingCharacters];
|
||||
}
|
||||
|
||||
- (int) activeSyncFolderType
|
||||
{
|
||||
if ([self isEqualToString: @"inbox"])
|
||||
return 2;
|
||||
else if ([self isEqualToString: @"draft"])
|
||||
return 3;
|
||||
else if ([self isEqualToString: @"sent"])
|
||||
return 5;
|
||||
else if ([self isEqualToString: @"trash"])
|
||||
return 4;
|
||||
|
||||
return 12;
|
||||
}
|
||||
|
||||
- (NSString *) realCollectionIdWithFolderType: (SOGoMicrosoftActiveSyncFolderType *) folderType;
|
||||
{
|
||||
NSString *realCollectionId, *v;
|
||||
|
||||
*folderType = ActiveSyncGenericFolder;
|
||||
v = [self stringByUnescapingURL];
|
||||
|
||||
if ([v hasPrefix: @"vevent/"])
|
||||
{
|
||||
realCollectionId = [v substringFromIndex: 7];
|
||||
*folderType = ActiveSyncEventFolder;
|
||||
}
|
||||
else if ([v hasPrefix: @"vtodo/"])
|
||||
{
|
||||
realCollectionId = [v substringFromIndex: 6];
|
||||
*folderType = ActiveSyncTaskFolder;
|
||||
}
|
||||
else if ([v hasPrefix: @"vcard/"])
|
||||
{
|
||||
realCollectionId = [v substringFromIndex: 6];
|
||||
*folderType = ActiveSyncContactFolder;
|
||||
}
|
||||
else if ([v hasPrefix: @"mail/"])
|
||||
{
|
||||
realCollectionId = [[v stringByUnescapingURL] substringFromIndex: 5];
|
||||
*folderType = ActiveSyncMailFolder;
|
||||
}
|
||||
else
|
||||
{
|
||||
realCollectionId = nil;
|
||||
}
|
||||
|
||||
return realCollectionId;
|
||||
}
|
||||
|
||||
//
|
||||
// 2014-01-16T05:00:00.000Z
|
||||
//
|
||||
// See http://www.gnustep.org/resources/documentation/Developer/Base/Reference/NSCalendarDate.html#method$NSCalendarDate-initWithString$calendarFormat$ for the format details.
|
||||
//
|
||||
- (NSCalendarDate *) calendarDate
|
||||
{
|
||||
NSString *s;
|
||||
id o;
|
||||
|
||||
// We force parsing in the GMT timezone. If we don't do that, the date will be parsed
|
||||
// in the default timezone.
|
||||
s = [NSString stringWithFormat: @"%@ GMT", self];
|
||||
o = [NSCalendarDate dateWithString: s calendarFormat: @"%Y%m%dT%H%M%SZ %Z"];
|
||||
|
||||
if (!o)
|
||||
o = [NSCalendarDate dateWithString: s calendarFormat: @"%Y-%m-%dT%H:%M:%S.%FZ %Z"];
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
- (NSString *) _valueForParameter: (NSString *) theParameter
|
||||
{
|
||||
NSMutableArray *components;
|
||||
NSString *s;
|
||||
int i;
|
||||
|
||||
components = [NSMutableArray arrayWithArray: [[[self componentsSeparatedByString: @"?"] lastObject] componentsSeparatedByString: @"&"]];
|
||||
|
||||
// We handle BASE64 encoded queryStrings. See http://msdn.microsoft.com/en-us/library/ee160227%28v=exchg.80%29.aspx for details.
|
||||
if ([components count] == 1)
|
||||
{
|
||||
NSString *deviceType, *parameterValue;
|
||||
NSData *queryString;
|
||||
|
||||
int cmd_code, deviceid_length, policy_length, devicetype_length, parameter_code, parameter_length, i;
|
||||
const char* qs_bytes;
|
||||
|
||||
queryString = [[components objectAtIndex: 0] dataByDecodingBase64];
|
||||
|
||||
if (![queryString length])
|
||||
return nil;
|
||||
|
||||
qs_bytes = (const char*)[queryString bytes];
|
||||
|
||||
if (!easCommandCodes)
|
||||
{
|
||||
easCommandCodes = [NSArray arrayWithObjects:@"Sync", @"SendMail", @"SmartForward", @"SmartReply", @"GetAttachment", @"na", @"na", @"na", @"na",
|
||||
@"FolderSync", @"FolderCreate", @"FolderDelete", @"FolderUpdate", @"MoveItems", @"GetItemEstimate", @"MeetingResponse",
|
||||
@"Search", @"Settings", @"Ping", @"ItemOperations", @"Provision", @"ResolveRecipients", @"ValidateCert", nil];
|
||||
RETAIN(easCommandCodes);
|
||||
}
|
||||
|
||||
if (!easCommandParameters)
|
||||
{
|
||||
easCommandParameters = [NSArray arrayWithObjects:@"AttachmentName", @"CollectionId", @"na", @"ItemId", @"LongId", @"na", @"Occurrence", @"Options", @"User", nil];
|
||||
RETAIN(easCommandParameters);
|
||||
}
|
||||
|
||||
// Command code, 1 byte, ie.: cmd=
|
||||
cmd_code = qs_bytes[1];
|
||||
[components addObject: [NSString stringWithFormat: @"cmd=%@", [easCommandCodes objectAtIndex: cmd_code]]];
|
||||
|
||||
// Device ID length and Device ID (variable)
|
||||
deviceid_length = qs_bytes[4];
|
||||
[components addObject: [NSString stringWithFormat: @"deviceId=%@", [[NSData encodeDataAsHexString: [queryString subdataWithRange: NSMakeRange(5, deviceid_length)]] uppercaseString]]];
|
||||
|
||||
// Device type length and type (variable)
|
||||
policy_length = qs_bytes[5+deviceid_length];
|
||||
devicetype_length = qs_bytes[5+deviceid_length+1+policy_length];
|
||||
deviceType = [[NSString alloc] initWithData: [queryString subdataWithRange: NSMakeRange(5+deviceid_length+1+policy_length+1, devicetype_length)]
|
||||
encoding: NSASCIIStringEncoding];
|
||||
AUTORELEASE(deviceType);
|
||||
|
||||
[components addObject: [NSString stringWithFormat: @"deviceType=%@", deviceType]];
|
||||
|
||||
// Command Parameters
|
||||
i = 5+deviceid_length+1+policy_length+1+devicetype_length;
|
||||
|
||||
while (i < [queryString length])
|
||||
{
|
||||
parameter_code = qs_bytes[i];
|
||||
parameter_length = qs_bytes[i+1];
|
||||
parameterValue = [[NSString alloc] initWithData: [queryString subdataWithRange: NSMakeRange(i+1+1, parameter_length)]
|
||||
encoding: NSASCIIStringEncoding];
|
||||
|
||||
AUTORELEASE(parameterValue);
|
||||
|
||||
// parameter_code 7 == Options
|
||||
// http://msdn.microsoft.com/en-us/library/ee237789(v=exchg.80).aspx
|
||||
if (parameter_code == 7)
|
||||
[components addObject: [NSString stringWithFormat: @"%@=%@", [easCommandParameters objectAtIndex: parameter_code],
|
||||
([parameterValue isEqualToString: @"\001"]) ? @"SaveInSent" : @"AcceptMultiPart"]];
|
||||
else
|
||||
[components addObject: [NSString stringWithFormat: @"%@=%@", [easCommandParameters objectAtIndex: parameter_code], parameterValue]];
|
||||
|
||||
i = i + 1 + 1 + parameter_length;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < [components count]; i++)
|
||||
{
|
||||
s = [components objectAtIndex: i];
|
||||
|
||||
if ([[s uppercaseString] hasPrefix: theParameter])
|
||||
return [s substringFromIndex: [theParameter length]];
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
//
|
||||
// This method extracts the "DeviceId" from a URI:
|
||||
//
|
||||
// /SOGo/Microsoft-Server-ActiveSync?Cmd=FolderSync&User=sogo10&DeviceId=SEC17CD1A3E9E3F2&DeviceType=SAMSUNGSGHI317M
|
||||
//
|
||||
- (NSString *) deviceId
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self _valueForParameter: @"DEVICEID="];
|
||||
|
||||
if (!s)
|
||||
s = @"Unknown";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
//
|
||||
// This method extracts the "DeviceType" from a URI:
|
||||
//
|
||||
// /SOGo/Microsoft-Server-ActiveSync?Cmd=FolderSync&User=sogo10&DeviceId=SEC17CD1A3E9E3F2&DeviceType=SAMSUNGSGHI317M
|
||||
//
|
||||
- (NSString *) deviceType
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self _valueForParameter: @"DEVICETYPE="];
|
||||
|
||||
if (!s)
|
||||
s = @"Unknown";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// This method extracts the "AttachmentName" from a URI:
|
||||
//
|
||||
// /SOGo/Microsoft-Server-ActiveSync?Cmd=GetAttachment&User=sogo&DeviceId=HTCa04b4932597acd3f2dc1a918b9728&DeviceType=htcvision&AttachmentName=mail/TestFldr/8/2
|
||||
//
|
||||
- (NSString *) attachmentName
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self _valueForParameter: @"ATTACHMENTNAME="];
|
||||
|
||||
if (!s)
|
||||
s = @"Unknown";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (NSString *) command
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self _valueForParameter: @"CMD="];
|
||||
|
||||
if (!s)
|
||||
s = @"Unknown";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
- (NSString *) itemid
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self _valueForParameter: @"ITEMID="];
|
||||
|
||||
if (!s)
|
||||
s = @"Unknown";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
- (NSString *) collectionid
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self _valueForParameter: @"COLLECTIONID="];
|
||||
|
||||
if (!s)
|
||||
s = @"Unknown";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
- (BOOL) acceptsMultiPart
|
||||
{
|
||||
NSString *s;
|
||||
|
||||
s = [self _valueForParameter: @"OPTIONS="];
|
||||
|
||||
if (s && [s rangeOfString: @"AcceptMultiPart" options: NSCaseInsensitiveSearch].location != NSNotFound)
|
||||
return YES;
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// FIXME: combine with our OpenChange code.
|
||||
//
|
||||
- (char) _decodeHexByte: (char) byteChar
|
||||
{
|
||||
char newByte;
|
||||
|
||||
if (byteChar >= 48 && byteChar <= 57)
|
||||
newByte = (uint8_t) byteChar - 48;
|
||||
else if (byteChar >= 65 && byteChar <= 70)
|
||||
newByte = (uint8_t) byteChar - 55;
|
||||
else if (byteChar >= 97 && byteChar <= 102)
|
||||
newByte = (uint8_t) byteChar - 87;
|
||||
else
|
||||
newByte = -1;
|
||||
|
||||
return newByte;
|
||||
}
|
||||
|
||||
//
|
||||
// FIXME: combine with our OpenChange code.
|
||||
//
|
||||
- (BOOL) _decodeHexByte: (uint8_t *) byte
|
||||
atPos: (NSUInteger) pos
|
||||
{
|
||||
BOOL error = NO;
|
||||
char newByte;
|
||||
unichar byteChar;
|
||||
|
||||
byteChar = [self characterAtIndex: pos];
|
||||
if (byteChar < 256)
|
||||
{
|
||||
newByte = [self _decodeHexByte: (char) byteChar];
|
||||
if (newByte == -1)
|
||||
error = YES;
|
||||
else
|
||||
*byte = newByte;
|
||||
}
|
||||
else
|
||||
error = YES;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
//
|
||||
// FIXME: combine with our OpenChange code.
|
||||
//
|
||||
- (BOOL) _decodeHexPair: (uint8_t *) byte
|
||||
atPos: (NSUInteger) pos
|
||||
{
|
||||
BOOL error;
|
||||
uint8_t lowValue, highValue;
|
||||
|
||||
error = [self _decodeHexByte: &highValue atPos: pos];
|
||||
if (!error)
|
||||
{
|
||||
error = [self _decodeHexByte: &lowValue atPos: pos + 1];
|
||||
if (!error)
|
||||
*byte = highValue << 4 | lowValue;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
//
|
||||
// FIXME: combine with our OpenChange code.
|
||||
//
|
||||
- (NSData *) convertHexStringToBytes
|
||||
{
|
||||
NSUInteger count, strLen, bytesLen;
|
||||
uint8_t *bytes, *currentByte;
|
||||
NSData *decoded = nil;
|
||||
BOOL error = NO;
|
||||
|
||||
strLen = [self length];
|
||||
if ((strLen % 2) == 0)
|
||||
{
|
||||
bytesLen = strLen / 2;
|
||||
bytes = NSZoneCalloc (NULL, bytesLen, sizeof (uint8_t));
|
||||
currentByte = bytes;
|
||||
for (count = 0; !error && count < strLen; count += 2)
|
||||
{
|
||||
error = [self _decodeHexPair: currentByte atPos: count];
|
||||
currentByte++;
|
||||
}
|
||||
if (error)
|
||||
NSZoneFree (NULL, bytes);
|
||||
else
|
||||
decoded = [NSData dataWithBytesNoCopy: bytes
|
||||
length: bytesLen
|
||||
freeWhenDone: YES];
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,12 +0,0 @@
|
||||
In order to use this software in production environments, you need to
|
||||
get a proper usage license from Microsoft. Please contact them directly
|
||||
to negotiate the fees associated to your user base.
|
||||
|
||||
To contact Microsoft, please visit:
|
||||
|
||||
http://www.microsoft.com/en-us/legal/intellectualproperty/
|
||||
|
||||
and send an email to iplicreq@microsoft.com
|
||||
|
||||
Inverse inc. provides this software for free, but is not responsible
|
||||
for anything related to its usage.
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __SOGOACTIVESYNCCONSTANTS_H__
|
||||
#define __SOGOACTIVESYNCCONSTANTS_H__
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ActiveSyncGenericFolder = 0,
|
||||
ActiveSyncMailFolder = 1,
|
||||
ActiveSyncContactFolder = 2,
|
||||
ActiveSyncEventFolder = 3,
|
||||
ActiveSyncTaskFolder = 4,
|
||||
} SOGoMicrosoftActiveSyncFolderType;
|
||||
|
||||
#endif
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __SOGOACTIVESYNCDISPATCHERSYNC_H__
|
||||
#define __SOGOACTIVESYNCDISPATCHERSYNC_H__
|
||||
|
||||
#import "SOGoActiveSyncDispatcher.h"
|
||||
|
||||
#import <DOM/DOMElement.h>
|
||||
#import <DOM/DOMProtocols.h>
|
||||
|
||||
@class WOResponse;
|
||||
|
||||
@interface SOGoActiveSyncDispatcher (Sync)
|
||||
|
||||
- (void) processSync: (id <DOMElement>) theDocumentElement
|
||||
inResponse: (WOResponse *) theResponse;
|
||||
|
||||
@end
|
||||
|
||||
#endif // SOGOACTIVESYNCDISPATCHERSYNC
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
#include "SOGoActiveSyncConstants.h"
|
||||
|
||||
@class NSException;
|
||||
@class NSURL;
|
||||
|
||||
@interface SOGoActiveSyncDispatcher : NSObject
|
||||
{
|
||||
NSURL *folderTableURL;
|
||||
id context;
|
||||
}
|
||||
|
||||
- (id) collectionFromId: (NSString *) theCollectionId
|
||||
type: (SOGoMicrosoftActiveSyncFolderType) theFolderType;
|
||||
|
||||
- (id) globallyUniqueIDToIMAPFolderName: (NSString *) theIdToTranslate
|
||||
type: (SOGoMicrosoftActiveSyncFolderType) theFolderType;
|
||||
|
||||
- (NSException *) dispatchRequest: (id) theRequest
|
||||
inResponse: (id) theResponse
|
||||
context: (id) theContext;
|
||||
|
||||
- (NSURL *) folderTableURL;
|
||||
- (void) ensureFolderTableExists;
|
||||
|
||||
@end
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __SOGOMAILOBJECTACTIVESYNC_H__
|
||||
#define __SOGOMAILOBJECTACTIVESYNC_H__
|
||||
|
||||
#import <Mailer/SOGoMailObject.h>
|
||||
|
||||
@class iCalCalendar;
|
||||
@class NSDictionary;
|
||||
@class WOContext;
|
||||
|
||||
@interface SOGoMailObject (ActiveSync)
|
||||
|
||||
- (iCalCalendar *) calendarFromIMIPMessage;
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __SOGOSYNCCACHEOBJECT_H__
|
||||
#define __SOGOSYNCCACHEOBJECT_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class NSNull;
|
||||
|
||||
@interface SOGoSyncCacheObject : NSObject
|
||||
{
|
||||
id _uid;
|
||||
id _sequence;
|
||||
}
|
||||
|
||||
+ (id) syncCacheObjectWithUID: (id) theUID sequence: (id) theSequence;
|
||||
- (id) uid;
|
||||
- (void) setUID: (id) theUID;
|
||||
- (id) sequence;
|
||||
- (void) setSequence: (id) theSequence;
|
||||
|
||||
- (NSComparisonResult) compareUID: (SOGoSyncCacheObject *) theSyncCacheObject;
|
||||
- (NSComparisonResult) compareSequence: (SOGoSyncCacheObject *) theSyncCacheObject;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "SOGoSyncCacheObject.h"
|
||||
|
||||
#import <Foundation/NSNull.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
@implementation SOGoSyncCacheObject
|
||||
|
||||
- (id) init
|
||||
{
|
||||
if ((self = [super init]))
|
||||
{
|
||||
_uid = nil;
|
||||
_sequence = nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id) syncCacheObjectWithUID: (id) theUID sequence: (id) theSequence;
|
||||
{
|
||||
id o;
|
||||
|
||||
o = [[self alloc] init];
|
||||
|
||||
[o setUID: theUID];
|
||||
[o setSequence: theSequence];
|
||||
|
||||
return [o autorelease];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(_uid);
|
||||
RELEASE(_sequence);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (id) uid
|
||||
{
|
||||
return _uid;
|
||||
}
|
||||
|
||||
- (void) setUID: (id) theUID
|
||||
{
|
||||
ASSIGN(_uid, theUID);
|
||||
}
|
||||
|
||||
- (id) sequence
|
||||
{
|
||||
return _sequence;
|
||||
}
|
||||
|
||||
- (void) setSequence: (id) theSequence
|
||||
{
|
||||
ASSIGN(_sequence, theSequence);
|
||||
}
|
||||
|
||||
|
||||
- (NSComparisonResult) compareUID: (SOGoSyncCacheObject *) theSyncCacheObject
|
||||
{
|
||||
return [[self uid] compare: [theSyncCacheObject uid]];
|
||||
}
|
||||
|
||||
//
|
||||
// We might get NSNull values here, so if both are NSNull instances,
|
||||
// we sort by UID. If both sequences are equal, we also sort by UID.
|
||||
//
|
||||
- (NSComparisonResult) compareSequence: (SOGoSyncCacheObject *) theSyncCacheObject
|
||||
{
|
||||
if ([[self sequence] isEqual: [NSNull null]] &&
|
||||
[[theSyncCacheObject sequence] isEqual: [NSNull null]])
|
||||
return [self compareUID: theSyncCacheObject];
|
||||
|
||||
if (![[self sequence] isEqual: [NSNull null]] && [[theSyncCacheObject sequence] isEqual: [NSNull null]])
|
||||
return NSOrderedDescending;
|
||||
|
||||
if ([[self sequence] isEqual: [NSNull null]] && ![[theSyncCacheObject sequence] isEqual: [NSNull null]])
|
||||
return NSOrderedAscending;
|
||||
|
||||
// Must check this here, to avoid comparing NSNull objects
|
||||
if ([[self sequence] compare: [theSyncCacheObject sequence]] == NSOrderedSame)
|
||||
return [self compareUID: theSyncCacheObject];
|
||||
|
||||
return [[self sequence] compare: [theSyncCacheObject sequence]];
|
||||
}
|
||||
|
||||
- (NSString *) description
|
||||
{
|
||||
return [NSString stringWithFormat: @"%@-%@", _uid, _sequence];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#import <NGObjWeb/SoObjectWebDAVDispatcher.h>
|
||||
|
||||
#include <NGObjWeb/SoObject+SoDAV.h>
|
||||
#include <NGObjWeb/WEClientCapabilities.h>
|
||||
#include <NGObjWeb/WOContext.h>
|
||||
#include <NGObjWeb/WORequest.h>
|
||||
#include <NGObjWeb/WOResponse.h>
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
|
||||
@interface SoObjectWebDAVDispatcher (ActiveSync)
|
||||
|
||||
- (id)_callObjectMethod:(NSString *)_method inContext:(WOContext *)_ctx;
|
||||
- (id) doOPTIONS:(WOContext *)_ctx;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SoObjectWebDAVDispatcher (ActiveSync)
|
||||
|
||||
- (id) doOPTIONS:(WOContext *)_ctx
|
||||
{
|
||||
WOResponse *response;
|
||||
|
||||
/*
|
||||
See example: http://msdn.microsoft.com/en-us/library/ee204257(v=exchg.80).aspx
|
||||
*/
|
||||
if ([[[_ctx request] requestHandlerKey] isEqualToString: @"Microsoft-Server-ActiveSync"])
|
||||
{
|
||||
response = [_ctx response];
|
||||
[response setStatus: 200];
|
||||
|
||||
[response setHeader: @"private" forKey: @"Cache-Control"];
|
||||
[response setHeader: @"OPTIONS, POST" forKey: @"Allow"];
|
||||
[response setHeader: @"14.1" forKey: @"MS-Server-ActiveSync"];
|
||||
[response setHeader: @"2.5,12.0,12.1,14.0,14.1" forKey: @"MS-ASProtocolVersions"];
|
||||
[response setHeader: @"Sync,SendMail,SmartForward,SmartReply,GetAttachment,GetHierarchy,CreateCollection,DeleteCollection,MoveCollection,FolderSync,FolderCreate,FolderDelete,FolderUpdate,MoveItems,GetItemEstimate,MeetingResponse,Search,Settings,Ping,ItemOperations,ResolveRecipients,ValidateCert" forKey: @"MS-ASProtocolCommands"];
|
||||
[response setHeader: @"OPTIONS, POST" forKey: @"Public"];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSArray *tmp;
|
||||
id result;
|
||||
|
||||
/* this checks whether the object provides a specific OPTIONS method */
|
||||
if ((result = [self _callObjectMethod:@"OPTIONS" inContext:_ctx]) != nil)
|
||||
return result;
|
||||
|
||||
response = [_ctx response];
|
||||
[response setStatus:200 /* OK */];
|
||||
|
||||
if ((tmp = [self->object davAllowedMethodsInContext:_ctx]) != nil)
|
||||
[response setHeader:[tmp componentsJoinedByString:@", "] forKey:@"allow"];
|
||||
|
||||
if ([[[_ctx request] clientCapabilities] isWebFolder]) {
|
||||
/*
|
||||
As described over here:
|
||||
http://teyc.editthispage.com/2005/06/02
|
||||
|
||||
This page also says that: "MS-Auth-Via header is not required to work
|
||||
with Web Folders".
|
||||
*/
|
||||
[response setHeader:[tmp componentsJoinedByString:@", "] forKey:@"public"];
|
||||
}
|
||||
|
||||
if ((tmp = [self->object davComplianceClassesInContext:_ctx]) != nil)
|
||||
[response setHeader:[tmp componentsJoinedByString:@", "] forKey:@"dav"];
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,34 +0,0 @@
|
||||
include ../config.make
|
||||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
include ../Version
|
||||
|
||||
NEEDS_GUI=no
|
||||
BUNDLE_EXTENSION = .SOGo
|
||||
BUNDLE_INSTALL_DIR = $(SOGO_LIBDIR)
|
||||
WOBUNDLE_EXTENSION = $(BUNDLE_EXTENSION)
|
||||
WOBUNDLE_INSTALL_DIR = $(BUNDLE_INSTALL_DIR)
|
||||
|
||||
# SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib
|
||||
|
||||
ADDITIONAL_INCLUDE_DIRS += \
|
||||
-I.. \
|
||||
-I../.. \
|
||||
-I../../SOPE
|
||||
|
||||
ADDITIONAL_LIB_DIRS += \
|
||||
-L../SoObjects/SOGo/SOGo.framework/Versions/Current/sogo \
|
||||
-L../SoObjects/SOGo/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L../SOPE/NGCards/$(GNUSTEP_OBJ_DIR)/ \
|
||||
-L/usr/local/lib \
|
||||
-Wl,-rpath,$(SOGO_SYSLIBDIR)/sogo
|
||||
|
||||
BUNDLE_LIBS += \
|
||||
-lSOGo \
|
||||
-lGDLContentStore \
|
||||
-lGDLAccess \
|
||||
-lNGObjWeb \
|
||||
-lNGCards -lNGMime -lNGLdap \
|
||||
-lNGStreams -lNGExtensions -lEOControl \
|
||||
-lDOM -lSaxObjC -lSBJson
|
||||
|
||||
ADDITIONAL_BUNDLE_LIBS += $(BUNDLE_LIBS)
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __ICALALARMACTIVESYNC_H__
|
||||
#define __ICALALARMACTIVESYNC_H__
|
||||
|
||||
#import <NGCards/iCalAlarm.h>
|
||||
|
||||
@class NSString;
|
||||
@class WOContext;
|
||||
|
||||
@interface iCalAlarm (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#import "iCalAlarm+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
|
||||
#import <NGCards/iCalAlarm.h>
|
||||
#import <NGCards/iCalEvent.h>
|
||||
#import <NGCards/iCalTrigger.h>
|
||||
|
||||
@implementation iCalAlarm (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSMutableString *s;
|
||||
|
||||
s = [NSMutableString string];
|
||||
|
||||
if ([[self action] caseInsensitiveCompare: @"DISPLAY"] == NSOrderedSame)
|
||||
{
|
||||
NSCalendarDate *nextAlarmDate;
|
||||
NSInteger delta;
|
||||
|
||||
nextAlarmDate = [self nextAlarmDate];
|
||||
delta = (int)(([[(iCalEvent *)parent startDate] timeIntervalSince1970] - [nextAlarmDate timeIntervalSince1970])/60);
|
||||
|
||||
// don't send negative reminder - not supported
|
||||
if (delta > 0)
|
||||
[s appendFormat: @"<Reminder xmlns=\"Calendar:\">%d</Reminder>", delta];
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
iCalTrigger *trigger;
|
||||
id o;
|
||||
|
||||
o = [theValues objectForKey: @"Reminder"];
|
||||
|
||||
// Outlook: if reminder is set to 0 minutes before start save it as 1 minute since -> 0 minutes in not accepted by SOGo
|
||||
if ([o isEqualToString: @"0"])
|
||||
o = @"1";
|
||||
|
||||
trigger = [iCalTrigger elementWithTag: @"TRIGGER"];
|
||||
[trigger setValueType: @"DURATION"];
|
||||
[self setTrigger: trigger];
|
||||
[self setAction: @"DISPLAY"];
|
||||
|
||||
// SOGo web ui only supports 1w but not 2w (custom reminder only supports min/hours/days)
|
||||
// 1week = -P1W
|
||||
// 2weeks > -PxD
|
||||
// xdays > -PxD
|
||||
// xhours -> -PTxH
|
||||
// xmin -> -PTxM
|
||||
if ([o intValue] == 10080)
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-P1W" ] forKey: @""];
|
||||
else
|
||||
{
|
||||
if (([o intValue] % 1440) == 0)
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-P%dD", ([o intValue] / 1440)] forKey: @""];
|
||||
else
|
||||
{
|
||||
if (([o intValue] % 60) == 0)
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-PT%dH", ([o intValue] / 60)] forKey: @""];
|
||||
else
|
||||
[trigger setSingleValue: [NSString stringWithFormat: @"-PT%@M", o] forKey: @""];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __ICALEVENTACTIVESYNC_H__
|
||||
#define __ICALEVENTACTIVESYNC_H__
|
||||
|
||||
#import <NGCards/iCalEvent.h>
|
||||
|
||||
@class NSString;
|
||||
@class WOContext;
|
||||
|
||||
@interface iCalEvent (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,598 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#import "iCalEvent+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
|
||||
#import <Appointments/iCalEntityObject+SOGo.h>
|
||||
|
||||
#include "iCalAlarm+ActiveSync.h"
|
||||
#include "iCalRecurrenceRule+ActiveSync.h"
|
||||
#include "iCalTimeZone+ActiveSync.h"
|
||||
#include "NSDate+ActiveSync.h"
|
||||
#include "NSString+ActiveSync.h"
|
||||
|
||||
@implementation iCalEvent (ActiveSync)
|
||||
|
||||
- (int) _attendeeStatus: (iCalPerson *) attendee
|
||||
{
|
||||
int attendee_status;
|
||||
|
||||
attendee_status = 5;
|
||||
if ([[attendee partStat] caseInsensitiveCompare: @"ACCEPTED"] == NSOrderedSame)
|
||||
attendee_status = 3;
|
||||
else if ([[attendee partStat] caseInsensitiveCompare: @"DECLINED"] == NSOrderedSame)
|
||||
attendee_status = 4;
|
||||
else if ([[attendee partStat] caseInsensitiveCompare: @"TENTATIVE"] == NSOrderedSame)
|
||||
attendee_status = 2;
|
||||
|
||||
return attendee_status;
|
||||
}
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSMutableString *s;
|
||||
NSArray *attendees, *categories;
|
||||
|
||||
iCalPerson *organizer, *attendee;
|
||||
iCalTimeZone *tz;
|
||||
id o;
|
||||
|
||||
int v, i, meetingStatus;
|
||||
|
||||
NSTimeZone *userTimeZone;
|
||||
userTimeZone = [[[context activeUser] userDefaults] timeZone];
|
||||
|
||||
s = [NSMutableString string];
|
||||
|
||||
[s appendFormat: @"<AllDayEvent xmlns=\"Calendar:\">%d</AllDayEvent>", ([self isAllDay] ? 1 : 0)];
|
||||
|
||||
// DTStamp -- http://msdn.microsoft.com/en-us/library/ee219470(v=exchg.80).aspx
|
||||
if ([self timeStampAsDate])
|
||||
[s appendFormat: @"<DTStamp xmlns=\"Calendar:\">%@</DTStamp>", [[self timeStampAsDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
else if ([self created])
|
||||
[s appendFormat: @"<DTStamp xmlns=\"Calendar:\">%@</DTStamp>", [[self created] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
|
||||
// StartTime -- http://msdn.microsoft.com/en-us/library/ee157132(v=exchg.80).aspx
|
||||
if ([self startDate])
|
||||
{
|
||||
if ([self isAllDay])
|
||||
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>",
|
||||
[[[self startDate] dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: ([userTimeZone secondsFromGMTForDate: [self startDate]])*-1]
|
||||
activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
else
|
||||
[s appendFormat: @"<StartTime xmlns=\"Calendar:\">%@</StartTime>", [[self startDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
|
||||
// EndTime -- http://msdn.microsoft.com/en-us/library/ee157945(v=exchg.80).aspx
|
||||
if ([self endDate])
|
||||
{
|
||||
if ([self isAllDay])
|
||||
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>",
|
||||
[[[self endDate] dateByAddingYears: 0 months: 0 days: 0
|
||||
hours: 0 minutes: 0
|
||||
seconds: ([userTimeZone secondsFromGMTForDate: [self endDate]])*-1]
|
||||
activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
else
|
||||
[s appendFormat: @"<EndTime xmlns=\"Calendar:\">%@</EndTime>", [[self endDate] activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
|
||||
// Timezone
|
||||
tz = [(iCalDateTime *)[self firstChildWithTag: @"dtstart"] timeZone];
|
||||
|
||||
if (!tz)
|
||||
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
|
||||
|
||||
[s appendFormat: @"<TimeZone xmlns=\"Calendar:\">%@</TimeZone>", [tz activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Organizer and other invitations related properties
|
||||
if ((organizer = [self organizer]))
|
||||
{
|
||||
meetingStatus = 1; // meeting and the user is the meeting organizer.
|
||||
o = [organizer rfc822Email];
|
||||
if ([o length])
|
||||
{
|
||||
[s appendFormat: @"<Organizer_Email xmlns=\"Calendar:\">%@</Organizer_Email>", o];
|
||||
|
||||
o = [organizer cn];
|
||||
if ([o length])
|
||||
[s appendFormat: @"<Organizer_Name xmlns=\"Calendar:\">%@</Organizer_Name>", o];
|
||||
}
|
||||
}
|
||||
|
||||
// Attendees
|
||||
attendees = [self attendees];
|
||||
|
||||
if ([attendees count])
|
||||
{
|
||||
int i, attendee_status, attendee_type;
|
||||
|
||||
[s appendString: @"<Attendees xmlns=\"Calendar:\">"];
|
||||
|
||||
for (i = 0; i < [attendees count]; i++)
|
||||
{
|
||||
[s appendString: @"<Attendee xmlns=\"Calendar:\">"];
|
||||
|
||||
attendee = [attendees objectAtIndex: i];
|
||||
[s appendFormat: @"<Attendee_Email xmlns=\"Calendar:\">%@</Attendee_Email>", [[attendee rfc822Email] activeSyncRepresentationInContext: context]];
|
||||
[s appendFormat: @"<Attendee_Name xmlns=\"Calendar:\">%@</Attendee_Name>", [[attendee cn] activeSyncRepresentationInContext: context]];
|
||||
|
||||
attendee_status = [self _attendeeStatus: attendee];
|
||||
|
||||
[s appendFormat: @"<Attendee_Status xmlns=\"Calendar:\">%d</Attendee_Status>", attendee_status];
|
||||
|
||||
// FIXME: handle resource
|
||||
if ([[attendee role] caseInsensitiveCompare: @"REQ-PARTICIPANT"] == NSOrderedSame)
|
||||
attendee_type = 1;
|
||||
else
|
||||
attendee_type = 2;
|
||||
|
||||
[s appendFormat: @"<Attendee_Type xmlns=\"Calendar:\">%d</Attendee_Type>", attendee_type];
|
||||
[s appendString: @"</Attendee>"];
|
||||
}
|
||||
[s appendString: @"</Attendees>"];
|
||||
}
|
||||
else
|
||||
{
|
||||
meetingStatus = 0; // appointment
|
||||
}
|
||||
|
||||
// This depends on the 'NEEDS-ACTION' parameter.
|
||||
// This will trigger the SendMail command
|
||||
if ([self userIsAttendee: [context activeUser]])
|
||||
{
|
||||
iCalPerson *attendee;
|
||||
|
||||
int attendee_status;
|
||||
|
||||
meetingStatus = 3; // event is a meeting, and the user is not the meeting organizer
|
||||
|
||||
attendee = [self userAsAttendee: [context activeUser]];
|
||||
attendee_status = [self _attendeeStatus: attendee];
|
||||
|
||||
[s appendFormat: @"<ResponseRequested xmlns=\"Calendar:\">%d</ResponseRequested>", 1];
|
||||
[s appendFormat: @"<ResponseType xmlns=\"Calendar:\">%d</ResponseType>", attendee_status];
|
||||
[s appendFormat: @"<DisallowNewTimeProposal xmlns=\"Calendar:\">%d</DisallowNewTimeProposal>", 1];
|
||||
|
||||
// BusyStatus -- http://msdn.microsoft.com/en-us/library/ee202290(v=exchg.80).aspx
|
||||
[s appendFormat: @"<BusyStatus xmlns=\"Calendar:\">%d</BusyStatus>", 2];
|
||||
}
|
||||
|
||||
[s appendFormat: @"<MeetingStatus xmlns=\"Calendar:\">%d</MeetingStatus>", meetingStatus];
|
||||
|
||||
// Subject -- http://msdn.microsoft.com/en-us/library/ee157192(v=exchg.80).aspx
|
||||
if ([[self summary] length])
|
||||
[s appendFormat: @"<Subject xmlns=\"Calendar:\">%@</Subject>", [[self summary] activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Location
|
||||
if ([[self location] length])
|
||||
[s appendFormat: @"<Location xmlns=\"Calendar:\">%@</Location>", [[self location] activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Importance - NOT SUPPORTED - DO NOT ENABLE
|
||||
//o = [self priority];
|
||||
//if ([o isEqualToString: @"9"])
|
||||
// v = 0;
|
||||
//else if ([o isEqualToString: @"1"])
|
||||
// v = 2;
|
||||
//else
|
||||
// v = 1;
|
||||
//[s appendFormat: @"<Importance xmlns=\"Calendar:\">%d</Importance>", v];
|
||||
|
||||
// UID -- http://msdn.microsoft.com/en-us/library/ee159919(v=exchg.80).aspx
|
||||
if ([[self uid] length])
|
||||
[s appendFormat: @"<UID xmlns=\"Calendar:\">%@</UID>", [self uid]];
|
||||
|
||||
// Sensitivity
|
||||
if ([[self accessClass] isEqualToString: @"PRIVATE"])
|
||||
v = 2;
|
||||
else if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
|
||||
v = 3;
|
||||
else
|
||||
v = 0;
|
||||
|
||||
[s appendFormat: @"<Sensitivity xmlns=\"Calendar:\">%d</Sensitivity>", v];
|
||||
|
||||
categories = [self categories];
|
||||
|
||||
if ([categories count])
|
||||
{
|
||||
[s appendFormat: @"<Categories xmlns=\"Calendar:\">"];
|
||||
for (i = 0; i < [categories count]; i++)
|
||||
{
|
||||
[s appendFormat: @"<Category xmlns=\"Calendar:\">%@</Category>", [[categories objectAtIndex: i] activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
[s appendFormat: @"</Categories>"];
|
||||
}
|
||||
|
||||
|
||||
// Reminder -- http://msdn.microsoft.com/en-us/library/ee219691(v=exchg.80).aspx
|
||||
// TODO: improve this to handle more alarm types
|
||||
if ([self hasAlarms])
|
||||
{
|
||||
iCalAlarm *alarm;
|
||||
|
||||
alarm = [self firstDisplayOrAudioAlarm];
|
||||
[s appendString: [alarm activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
// Recurrence rules
|
||||
if ([self isRecurrent])
|
||||
{
|
||||
[s appendString: [[[self recurrenceRules] lastObject] activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
// Comment
|
||||
o = [self comment];
|
||||
if ([o length])
|
||||
{
|
||||
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
|
||||
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
|
||||
o = [o activeSyncRepresentationInContext: context];
|
||||
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
[s appendFormat: @"<Body xmlns=\"Calendar:\">%@</Body>", o];
|
||||
[s appendString: @"<BodyTruncated xmlns=\"Calendar:\">0</BodyTruncated>"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
[s appendFormat: @"<Type>%d</Type>", 1];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
|
||||
[s appendFormat: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
}
|
||||
|
||||
[s appendFormat: @"<NativeBodyType xmlns=\"AirSyncBase:\">%d</NativeBodyType>", 1];
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
//
|
||||
// To understand meeting requests/responses, see:
|
||||
//
|
||||
// http://blogs.msdn.com/b/exchangedev/archive/2011/07/22/working-with-meeting-requests-in-exchange-activesync.aspx
|
||||
// http://blogs.msdn.com/b/exchangedev/archive/2011/07/29/working-with-meeting-responses-in-exchange-activesync.aspx
|
||||
//
|
||||
//
|
||||
// Here is an example of a Sync call when sogo10 accepts an invitation from sogo3:
|
||||
//
|
||||
// <Change>
|
||||
// <ServerId>2978-52EA9D00-1-A253E70.ics</ServerId>
|
||||
// <ApplicationData>
|
||||
// <TimeZone xmlns="Calendar:">LAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsAAAABAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAACAAIAAAAAAAAAxP///w==</TimeZone>
|
||||
// <AllDayEvent xmlns="Calendar:">0</AllDayEvent>
|
||||
// <StartTime xmlns="Calendar:">20140207T130000Z</StartTime>
|
||||
// <EndTime xmlns="Calendar:">20140207T140000Z</EndTime>
|
||||
// <DTStamp xmlns="Calendar:">20140130T185245Z</DTStamp>
|
||||
// <Subject xmlns="Calendar:">test 8</Subject>
|
||||
// <Sensitivity xmlns="Calendar:">0</Sensitivity>
|
||||
// <Body xmlns="AirSyncBase:">
|
||||
// <Type>1</Type>
|
||||
// <Data/>
|
||||
// </Body>
|
||||
// <Organizer_Email xmlns="Calendar:">sogo3@example.com</Organizer_Email>
|
||||
// <UID xmlns="Calendar:">2978-52EA9D00-1-A253E70</UID>
|
||||
// <Attendees xmlns="Calendar:">
|
||||
// <Attendee>
|
||||
// <Attendee_Name>sogo10</Attendee_Name>
|
||||
// <Attendee_Email>sogo10@example.com</Attendee_Email>
|
||||
// <Attendee_Type>1</Attendee_Type>
|
||||
// </Attendee>
|
||||
// </Attendees>
|
||||
// <BusyStatus xmlns="Calendar:">2</BusyStatus>
|
||||
// <MeetingStatus xmlns="Calendar:">3</MeetingStatus>
|
||||
// <Organizer_Name xmlns="Calendar:">Wolfgang Fritz</Organizer_Name>
|
||||
// </ApplicationData>
|
||||
// </Change>
|
||||
//
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
iCalDateTime *start, *end;
|
||||
NSTimeZone *userTimeZone;
|
||||
iCalTimeZone *tz;
|
||||
id o;
|
||||
|
||||
BOOL isAllDay;
|
||||
|
||||
if ((o = [theValues objectForKey: @"UID"]))
|
||||
[self setUid: o];
|
||||
|
||||
// FIXME: merge with iCalToDo
|
||||
if ((o = [theValues objectForKey: @"Subject"]))
|
||||
[self setSummary: o];
|
||||
|
||||
isAllDay = NO;
|
||||
if ([[theValues objectForKey: @"AllDayEvent"] intValue])
|
||||
{
|
||||
isAllDay = YES;
|
||||
}
|
||||
|
||||
//
|
||||
// 0- free, 1- tentative, 2- busy and 3- out of office
|
||||
//
|
||||
if ((o = [theValues objectForKey: @"BusyStatus"]))
|
||||
{
|
||||
[o intValue];
|
||||
}
|
||||
|
||||
//
|
||||
// 0- normal, 1- personal, 2- private and 3-confidential
|
||||
//
|
||||
if ((o = [theValues objectForKey: @"Sensitivity"]))
|
||||
{
|
||||
switch ([o intValue])
|
||||
{
|
||||
case 2:
|
||||
[self setAccessClass: @"PRIVATE"];
|
||||
break;
|
||||
case 3:
|
||||
[self setAccessClass: @"CONFIDENTIAL"];
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
default:
|
||||
[self setAccessClass: @"PUBLIC"];
|
||||
}
|
||||
}
|
||||
|
||||
// Categories
|
||||
if ((o = [theValues objectForKey: @"Categories"]) && [o length])
|
||||
[self setCategories: o];
|
||||
|
||||
// We ignore TimeZone sent by mobile devices for now.
|
||||
// Some Windows devices don't send during event updates.
|
||||
//if ((o = [theValues objectForKey: @"TimeZone"]))
|
||||
// {
|
||||
// }
|
||||
//else
|
||||
{
|
||||
// We haven't received a timezone, let's use the user's timezone
|
||||
// specified in SOGo for now.
|
||||
userTimeZone = [[[context activeUser] userDefaults] timeZone];
|
||||
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
|
||||
[(iCalCalendar *) parent addTimeZone: tz];
|
||||
}
|
||||
|
||||
// FIXME: merge with iCalToDo
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
if ((o = [theValues objectForKey: @"Body"]))
|
||||
[self setComment: o];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
||||
[self setComment: o];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"Location"]))
|
||||
[self setLocation: o];
|
||||
|
||||
if ((o = [theValues objectForKey: @"StartTime"]))
|
||||
{
|
||||
o = [o calendarDate];
|
||||
start = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
|
||||
[start setTimeZone: tz];
|
||||
|
||||
if (isAllDay)
|
||||
{
|
||||
[start setDate: o];
|
||||
[start setTimeZone: nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
[start setDateTime: o];
|
||||
}
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"EndTime"]))
|
||||
{
|
||||
o = [o calendarDate];
|
||||
end = (iCalDateTime *) [self uniqueChildWithTag: @"dtend"];
|
||||
[end setTimeZone: tz];
|
||||
|
||||
if (isAllDay)
|
||||
{
|
||||
[end setDate: o];
|
||||
[end setTimeZone: nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
[end setDateTime: o];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// If an alarm is deinfed with an action != DISPLAY, we ignore the alarm - don't want to overwrite.
|
||||
//
|
||||
if ([self hasAlarms] && [[[[self alarms] objectAtIndex: 0] action] caseInsensitiveCompare: @"DISPLAY"] != NSOrderedSame)
|
||||
{
|
||||
// Ignore the alarm for now
|
||||
}
|
||||
else if ((o = [theValues objectForKey: @"Reminder"]))
|
||||
{
|
||||
// NOTE: Outlook sends a 15 min reminder (18 hour for allday) if no reminder is specified
|
||||
// although no default reminder is defined (File -> Options -> Clendar -> Calendar Options - > Default Reminders)
|
||||
//
|
||||
// http://answers.microsoft.com/en-us/office/forum/office_2013_release-outlook/desktop-outlook-calendar-creates-entries-with/9aef72d8-81bb-4a32-a6ab-bf7d216fb811?page=5&tm=1395690285088
|
||||
//
|
||||
iCalAlarm *alarm;
|
||||
|
||||
alarm = [[iCalAlarm alloc] init];
|
||||
[alarm takeActiveSyncValues: theValues inContext: context];
|
||||
|
||||
[self removeAllAlarms];
|
||||
[self addToAlarms: alarm];
|
||||
RELEASE(alarm);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We remove existing alarm since no reminder in the ActiveSync payload
|
||||
[self removeAllAlarms];
|
||||
}
|
||||
|
||||
// Recurrence
|
||||
if ((o = [theValues objectForKey: @"Recurrence"]))
|
||||
{
|
||||
iCalRecurrenceRule *rule;
|
||||
|
||||
rule = [[iCalRecurrenceRule alloc] init];
|
||||
[self setRecurrenceRules: [NSArray arrayWithObject: rule]];
|
||||
RELEASE(rule);
|
||||
|
||||
[rule takeActiveSyncValues: o inContext: context];
|
||||
}
|
||||
|
||||
// Organizer - we don't touch the value unless we're the organizer
|
||||
if ((o = [theValues objectForKey: @"Organizer_Email"]) &&
|
||||
([self userIsOrganizer: [context activeUser]] || [[context activeUser] hasEmail: o]))
|
||||
{
|
||||
iCalPerson *person;
|
||||
|
||||
person = [iCalPerson elementWithTag: @"organizer"];
|
||||
[person setEmail: o];
|
||||
[person setCn: [theValues objectForKey: @"Organizer_Name"]];
|
||||
[person setPartStat: @"ACCEPTED"];
|
||||
[self setOrganizer: person];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"MeetingStatus"]))
|
||||
{
|
||||
//
|
||||
// iOS is plain stupid here. It seends event invitations with no Organizer.
|
||||
// We check this corner-case and if MeetingStatus == 1 (see http://msdn.microsoft.com/en-us/library/ee219342(v=exchg.80).aspx or details)
|
||||
// and there's no organizer, we fake one.
|
||||
//
|
||||
if ([o intValue] == 1 && ![theValues objectForKey: @"Organizer_Email"] && ![[[self organizer] rfc822Email] length])
|
||||
{
|
||||
iCalPerson *person;
|
||||
|
||||
person = [iCalPerson elementWithTag: @"organizer"];
|
||||
[person setEmail: [[[context activeUser] primaryIdentity] objectForKey: @"email"]];
|
||||
[person setCn: [[context activeUser] cn]];
|
||||
[person setPartStat: @"ACCEPTED"];
|
||||
[self setOrganizer: person];
|
||||
}
|
||||
|
||||
//
|
||||
// When MeetingResponse fails Outlook still sends a new calendar entry with MeetingStatus=3.
|
||||
// Use the organizer from the request if the event has no organizer.
|
||||
//
|
||||
if ([o intValue] == 3 && [theValues objectForKey: @"Organizer_Email"] && ![[[self organizer] rfc822Email] length])
|
||||
{
|
||||
iCalPerson *person;
|
||||
person = [iCalPerson elementWithTag: @"organizer"];
|
||||
[person setEmail: [theValues objectForKey: @"Organizer_Email"]];
|
||||
[person setCn: [theValues objectForKey: @"Organizer_Name"]];
|
||||
[person setPartStat: @"ACCEPTED"];
|
||||
[self setOrganizer: person];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Attendees - we don't touch the values if we're an attendee. This is gonna
|
||||
// be done automatically by the ActiveSync client when invoking MeetingResponse.
|
||||
if (![self userIsAttendee: [context activeUser]])
|
||||
{
|
||||
// Windows phones sens sometimes an empty Attendees tag.
|
||||
// We check it's an array before processing it.
|
||||
if ((o = [theValues objectForKey: @"Attendees"])&& [o isKindOfClass: [NSArray class]])
|
||||
{
|
||||
NSMutableArray *attendees;
|
||||
NSDictionary *attendee;
|
||||
iCalPerson *person;
|
||||
int status, i;
|
||||
|
||||
attendees = [NSMutableArray array];
|
||||
|
||||
for (i = 0; i < [o count]; i++)
|
||||
{
|
||||
// Each attendee has is a dictionary similar to this:
|
||||
// { "Attendee_Email" = "sogo3@example.com"; "Attendee_Name" = "Wolfgang Fritz"; "Attendee_Status" = 5; "Attendee_Type" = 1; }
|
||||
attendee = [o objectAtIndex: i];
|
||||
|
||||
person = [iCalPerson elementWithTag: @"attendee"];
|
||||
[person setCn: [attendee objectForKey: @"Attendee_Name"]];
|
||||
[person setEmail: [attendee objectForKey: @"Attendee_Email"]];
|
||||
|
||||
status = [[attendee objectForKey: @"Attendee_Status"] intValue];
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case 2:
|
||||
[person setPartStat: @"TENTATIVE"];
|
||||
break;
|
||||
case 3:
|
||||
[person setPartStat: @"ACCEPTED"];
|
||||
break;
|
||||
case 4:
|
||||
[person setPartStat: @"DECLINED"];
|
||||
break;
|
||||
case 0:
|
||||
case 5:
|
||||
default:
|
||||
[person setPartStat: @"NEEDS-ACTION"];
|
||||
break;
|
||||
}
|
||||
|
||||
// FIXME: handle Attendee_Type
|
||||
|
||||
[attendees addObject: person];
|
||||
}
|
||||
|
||||
[self setAttendees: attendees];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __ICALRECURRENCERULEACTIVESYNC_H__
|
||||
#define __ICALRECURRENCERULEACTIVESYNC_H__
|
||||
|
||||
#import <NGCards/iCalRecurrenceRule.h>
|
||||
|
||||
@class NSDictionary;
|
||||
@class NSString;
|
||||
@class WOContext;
|
||||
|
||||
@interface iCalRecurrenceRule (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext:(WOContext *) context;
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,372 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#import "iCalRecurrenceRule+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGCards/iCalEvent.h>
|
||||
#import <NGCards/iCalByDayMask.h>
|
||||
|
||||
#import "NSCalendarDate+ActiveSync.h"
|
||||
#import "NSDate+ActiveSync.h"
|
||||
|
||||
@implementation iCalRecurrenceRule (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSMutableString *s;
|
||||
int type;
|
||||
|
||||
s = [NSMutableString string];
|
||||
|
||||
[s appendString: @"<Recurrence xmlns=\"Calendar:\">"];
|
||||
|
||||
// 0 -> daily, 1 -> weekly, 2 -> montly, 5 -> yearly
|
||||
type = 0;
|
||||
|
||||
if ([self frequency] == iCalRecurrenceFrequenceDaily)
|
||||
{
|
||||
type = 0;
|
||||
|
||||
// 1 -> sunday, 2 -> monday, 4 -> tuesday, 8 -> wednesday, 16 -> thursday, 32 -> friday, 64 -> saturday, 127 -> last day of month (montly or yearl recurrences only)
|
||||
if ([[self byDayMask] isWeekDays])
|
||||
{
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (2|4|8|16|32)];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendFormat: @"<Recurrence_Interval xmlns=\"Calendar:\">%d</Recurrence_Interval>", [self repeatInterval]];
|
||||
}
|
||||
}
|
||||
else if ([self frequency] == iCalRecurrenceFrequenceWeekly)
|
||||
{
|
||||
iCalWeekOccurrences *occurrences;
|
||||
int i, v;
|
||||
|
||||
type = 1;
|
||||
|
||||
occurrences = [[self byDayMask] weekDayOccurrences];
|
||||
v = 0;
|
||||
|
||||
if (occurrences)
|
||||
{
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
if (occurrences[0][i])
|
||||
v += (1 << i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No byDayMask, we take the event's start date to compute the DayOfWeek
|
||||
// 0 == Sunday, 6 == Saturday
|
||||
v = (1 << [[[self parent] startDate] dayOfWeek]);
|
||||
}
|
||||
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", v];
|
||||
[s appendFormat: @"<Recurrence_Interval xmlns=\"Calendar:\">%d</Recurrence_Interval>", [self repeatInterval]];
|
||||
}
|
||||
else if ([self frequency] == iCalRecurrenceFrequenceMonthly)
|
||||
{
|
||||
if ([[self byDay] length])
|
||||
{
|
||||
int firstOccurrence;
|
||||
iCalByDayMask *dm;
|
||||
|
||||
type = 3; // recurs monthly on the nth day
|
||||
dm = [self byDayMask];
|
||||
firstOccurrence = [dayMask firstOccurrence];
|
||||
|
||||
// Handle the case for "Last day of the month"
|
||||
if (firstOccurrence < 0)
|
||||
firstOccurrence = 5;
|
||||
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (1 << [dm firstDay])];
|
||||
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"Calendar:\">%d</Recurrence_WeekOfMonth>", firstOccurrence];
|
||||
}
|
||||
else if ([[self byMonthDay] count])
|
||||
{
|
||||
NSArray *days;
|
||||
|
||||
type = 2; // recurs monthly
|
||||
days = [self byMonthDay];
|
||||
if ([days count] > 0 && [[days objectAtIndex: 0] intValue] < 0)
|
||||
{
|
||||
// Last day of the month
|
||||
iCalByDayMask *dm;
|
||||
|
||||
dm = [self byDayMask];
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (1 << [dm firstDay])];
|
||||
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"Calendar:\">%d</Recurrence_WeekOfMonth>", 5];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unsupported rule in ActiveSync/Outlook. Rule that says "Repeat on the 7th and 8th of each month".
|
||||
// FIXME
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Simple reccurrence rule of type "Monthly"
|
||||
type = 2;
|
||||
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"Calendar:\">%d</Recurrence_DayOfMonth>",
|
||||
[[[self parent] startDate] dayOfMonth]];
|
||||
}
|
||||
}
|
||||
else if ([self frequency] == iCalRecurrenceFrequenceYearly)
|
||||
{
|
||||
type = 6; // Yearly on the nth day
|
||||
|
||||
if ([[self flattenedValuesForKey: @"bymonth"] length])
|
||||
{
|
||||
if ([[self byDay] length])
|
||||
{
|
||||
int firstOccurrence;
|
||||
iCalByDayMask *dm;
|
||||
|
||||
dm = [self byDayMask];
|
||||
firstOccurrence = [dm firstOccurrence];
|
||||
if (firstOccurrence < 0)
|
||||
firstOccurrence = 5;
|
||||
|
||||
[s appendFormat: @"<Recurrence_DayOfWeek xmlns=\"Calendar:\">%d</Recurrence_DayOfWeek>", (1 << [dm firstDay])];
|
||||
[s appendFormat: @"<Recurrence_WeekOfMonth xmlns=\"Calendar:\">%d</Recurrence_WeekOfMonth>", firstOccurrence];
|
||||
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"Calendar:\">%@</Recurrence_MonthOfYear>",
|
||||
[self flattenedValuesForKey: @"bymonth"]];
|
||||
}
|
||||
else
|
||||
{
|
||||
type = 5; // Yearly
|
||||
|
||||
[s appendFormat: @"<Recurrence_DayOfMonth xmlns=\"Calendar:\">%@</Recurrence_DayOfMonth>",
|
||||
[self flattenedValuesForKey: @"bymonthday"]];
|
||||
|
||||
[s appendFormat: @"<Recurrence_MonthOfYear xmlns=\"Calendar:\">%@</Recurrence_MonthOfYear>",
|
||||
[self flattenedValuesForKey: @"bymonth"]];
|
||||
}
|
||||
}
|
||||
else
|
||||
type = 5;
|
||||
}
|
||||
|
||||
[s appendFormat: @"<Recurrence_Type xmlns=\"Calendar:\">%d</Recurrence_Type>", type];
|
||||
|
||||
// Occurrences / Until
|
||||
//[s appendFormat: @"<Recurrence_Occurrences xmlns=\"Calendar:\">%d</Recurrence_Occurrences>", 5];
|
||||
if ([self repeatCount])
|
||||
{
|
||||
[s appendFormat: @"<Recurrence_Occurrences xmlns=\"Calendar:\">%@</Recurrence_Occurrences>",
|
||||
[self flattenedValuesForKey: @"count"]];
|
||||
}
|
||||
else if ([self untilDate])
|
||||
{
|
||||
NSCalendarDate *date;
|
||||
|
||||
date = [self untilDate];
|
||||
//ud = [[context activeUser] userDefaults];
|
||||
//[date setTimeZone: [ud timeZone]];
|
||||
|
||||
[s appendFormat: @"<Recurrence_Until xmlns=\"Calendar:\">%@</Recurrence_Until>",
|
||||
[date activeSyncRepresentationWithoutSeparatorsInContext: context]];
|
||||
}
|
||||
|
||||
|
||||
[s appendString: @"</Recurrence>"];
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) _setByDayFromValues: (NSDictionary *) theValues
|
||||
{
|
||||
NSString *day;
|
||||
id o;
|
||||
|
||||
unsigned int day_of_week;
|
||||
int i, week_of_month;
|
||||
|
||||
o = [theValues objectForKey: @"Recurrence_DayOfWeek"];
|
||||
|
||||
// The documentation says WeekOfMonth must be between 1 and 5. The value
|
||||
// 5 means "last week of month"
|
||||
week_of_month = [[theValues objectForKey: @"Recurrence_WeekOfMonth"] intValue];
|
||||
|
||||
if (week_of_month > 4)
|
||||
week_of_month = -1;
|
||||
|
||||
// We find the correct day of the week
|
||||
day_of_week = [o intValue];
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
if ((1<<i) == day_of_week)
|
||||
{
|
||||
day_of_week = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
day = [self iCalRepresentationForWeekDay: i];
|
||||
|
||||
[self setSingleValue: [NSString stringWithFormat: @"%d%@",
|
||||
week_of_month, day]
|
||||
forKey: @"byday"];
|
||||
}
|
||||
|
||||
- (void) _setByMonthFromValues: (NSDictionary *) theValues
|
||||
{
|
||||
unsigned int month_of_year;
|
||||
|
||||
month_of_year = [[theValues objectForKey: @"Recurrence_MonthOfYear"] intValue];
|
||||
|
||||
[self setSingleValue: [NSString stringWithFormat: @"%d", month_of_year]
|
||||
forKey: @"bymonth"];
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
id o;
|
||||
|
||||
int recurrenceType;
|
||||
|
||||
recurrenceType = [[theValues objectForKey: @"Recurrence_Type"] intValue];
|
||||
|
||||
if ((o = [theValues objectForKey: @"Recurrence_Interval"]))
|
||||
{
|
||||
[self setRepeatInterval: [o intValue]];
|
||||
}
|
||||
else
|
||||
[self setRepeatInterval: 1];
|
||||
|
||||
switch (recurrenceType)
|
||||
{
|
||||
//
|
||||
// Daily
|
||||
//
|
||||
case 0:
|
||||
[self setFrequency: iCalRecurrenceFrequenceDaily];
|
||||
|
||||
|
||||
// Every weekday
|
||||
if ((o = [theValues objectForKey: @"Recurrence_DayOfWeek"]))
|
||||
{
|
||||
[self setByDayMask: [iCalByDayMask byDayMaskWithWeekDays]];
|
||||
}
|
||||
break;
|
||||
//
|
||||
// Weekly
|
||||
//
|
||||
case 1:
|
||||
[self setFrequency: iCalRecurrenceFrequenceWeekly];
|
||||
|
||||
// 42 == Every Monday, Wednesday and Friday, for example
|
||||
if ((o = [theValues objectForKey: @"Recurrence_DayOfWeek"]))
|
||||
{
|
||||
iCalWeekOccurrences days;
|
||||
unsigned int i, v;
|
||||
|
||||
memset(days, 0, 7 * sizeof(iCalWeekOccurrence));
|
||||
v = [o intValue];
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
if (v & (1<<i))
|
||||
days[i] = iCalWeekOccurrenceAll;
|
||||
}
|
||||
|
||||
[self setByDayMask: [iCalByDayMask byDayMaskWithDays: days]];
|
||||
}
|
||||
break;
|
||||
//
|
||||
// Montly
|
||||
//
|
||||
case 2:
|
||||
case 3:
|
||||
[self setFrequency: iCalRecurrenceFrequenceMonthly];
|
||||
|
||||
// The 5th of every X month(s)
|
||||
if ((o = [theValues objectForKey: @"Recurrence_DayOfMonth"]))
|
||||
{
|
||||
[self setValues: [NSArray arrayWithObject: o]
|
||||
atIndex: 0 forKey: @"bymonthday"];
|
||||
}
|
||||
// The 3rd Thursay every X month(s)
|
||||
else if ((o = [theValues objectForKey: @"Recurrence_DayOfWeek"]))
|
||||
{
|
||||
[self _setByDayFromValues: theValues];
|
||||
}
|
||||
|
||||
break;
|
||||
//
|
||||
// Yearly
|
||||
//
|
||||
case 5:
|
||||
case 6:
|
||||
default:
|
||||
[self setFrequency: iCalRecurrenceFrequenceYearly];
|
||||
|
||||
// On April 19th
|
||||
if ((o = [theValues objectForKey: @"Recurrence_DayOfMonth"]))
|
||||
{
|
||||
[self setValues: [NSArray arrayWithObject: o] atIndex: 0
|
||||
forKey: @"bymonthday"];
|
||||
|
||||
[self _setByMonthFromValues: theValues];
|
||||
}
|
||||
else
|
||||
{
|
||||
// On the Second Wednesday of April
|
||||
[self _setByDayFromValues: theValues];
|
||||
[self _setByMonthFromValues: theValues];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"Recurrence_Occurrences"]))
|
||||
{
|
||||
[self setRepeatCount: [o intValue]];
|
||||
}
|
||||
else if ((o = [theValues objectForKey: @"Recurrence_Until"]))
|
||||
{
|
||||
[self setUntilDate: [o calendarDate]];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __ICALTIMEZONEACTIVESYNC_H__
|
||||
#define __ICALTIMEZONEACTIVESYNC_H__
|
||||
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
|
||||
@class NSString;
|
||||
@class WOContext;
|
||||
|
||||
@interface iCalTimeZone (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#import "iCalTimeZone+ActiveSync.h"
|
||||
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <Foundation/NSCalendarDate.h>
|
||||
#include <Foundation/NSData.h>
|
||||
#include <Foundation/NSDate.h>
|
||||
#include <Foundation/NSString.h>
|
||||
|
||||
#import <NGCards/iCalByDayMask.h>
|
||||
#import <NGCards/iCalTimeZonePeriod.h>
|
||||
#import <NGCards/iCalRecurrenceRule.h>
|
||||
|
||||
#import <NGExtensions/NGBase64Coding.h>
|
||||
|
||||
#include "NSData+ActiveSync.h"
|
||||
|
||||
struct SYSTEMTIME {
|
||||
uint16_t wYear;
|
||||
uint16_t wMonth;
|
||||
uint16_t wDayOfWeek;
|
||||
uint16_t wDay;
|
||||
uint16_t wHour;
|
||||
uint16_t wMinute;
|
||||
uint16_t wSecond;
|
||||
uint16_t wMilliseconds;
|
||||
};
|
||||
|
||||
@interface iCalTimeZonePeriod (ActiveSync)
|
||||
|
||||
- (void) _fillTZDate: (struct SYSTEMTIME *) tzData;
|
||||
|
||||
@end
|
||||
|
||||
@implementation iCalTimeZonePeriod (ActiveSync)
|
||||
|
||||
//
|
||||
// FIXME - combine with iCalTimeZone+MAPIStore.m
|
||||
//
|
||||
- (void) _fillTZDate: (struct SYSTEMTIME *) tzData
|
||||
{
|
||||
iCalRecurrenceRule *rrule;
|
||||
NSArray *byMonth;
|
||||
iCalByDayMask *mask;
|
||||
NSCalendarDate *dateValue;
|
||||
|
||||
rrule = [self recurrenceRule];
|
||||
byMonth = [rrule byMonth];
|
||||
if ([byMonth count] > 0)
|
||||
{
|
||||
tzData->wYear = 0;
|
||||
tzData->wMonth = [[byMonth objectAtIndex: 0] intValue];
|
||||
mask = [rrule byDayMask];
|
||||
tzData->wDayOfWeek = [mask firstDay];
|
||||
tzData->wDay = ([mask firstOccurrence] == -1) ? 5 : [mask firstOccurrence];
|
||||
|
||||
dateValue = [self startDate];
|
||||
tzData->wHour = [dateValue hourOfDay];
|
||||
tzData->wMinute = [dateValue minuteOfHour];
|
||||
tzData->wSecond = [dateValue secondOfMinute];
|
||||
tzData->wMilliseconds = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation iCalTimeZone (ActiveSync)
|
||||
|
||||
//
|
||||
// FIXME - combine with iCalTimeZone+MAPIStore.m
|
||||
//
|
||||
- (iCalTimeZonePeriod *) _mostRecentPeriodWithName: (NSString *) periodName
|
||||
{
|
||||
NSArray *periods;
|
||||
iCalTimeZonePeriod *period;
|
||||
NSUInteger max;
|
||||
|
||||
periods = [self childrenWithTag: periodName];
|
||||
max = [periods count];
|
||||
if (max > 0)
|
||||
{
|
||||
periods = [periods sortedArrayUsingSelector: @selector (compare:)];
|
||||
period = (iCalTimeZonePeriod *) [periods objectAtIndex: (max - 1)];
|
||||
}
|
||||
else
|
||||
period = nil;
|
||||
|
||||
return period;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
iCalTimeZonePeriod *period;
|
||||
NSMutableData *bytes;
|
||||
|
||||
uint32_t lBias;
|
||||
uint32_t lStandardBias;
|
||||
uint32_t lDaylightBias;
|
||||
//uint16_t wStandardYear;
|
||||
struct SYSTEMTIME stStandardDate;
|
||||
//uint16_t wDaylightYear;
|
||||
struct SYSTEMTIME stDaylightDate;
|
||||
|
||||
char standardName[64], daylightName[64];
|
||||
|
||||
bytes = [NSMutableData data];
|
||||
|
||||
memset(standardName, 0, 64);
|
||||
memset(daylightName, 0, 64);
|
||||
lStandardBias = 0;
|
||||
|
||||
period = [self _mostRecentPeriodWithName: @"STANDARD"];
|
||||
lBias = -[period secondsOffsetFromGMT] / 60;
|
||||
[period _fillTZDate: &stStandardDate];
|
||||
|
||||
period = [self _mostRecentPeriodWithName: @"DAYLIGHT"];
|
||||
if (!period)
|
||||
stStandardDate.wMonth = 0;
|
||||
|
||||
lDaylightBias = (uint32_t) -([period secondsOffsetFromGMT] / 60) - lBias;
|
||||
[period _fillTZDate: &stDaylightDate];
|
||||
//wStandardYear = stStandardDate.wYear;
|
||||
//wDaylightYear = stDaylightDate.wYear;
|
||||
|
||||
|
||||
// We build the timezone
|
||||
[bytes appendBytes: &lBias length: 4];
|
||||
[bytes appendBytes: standardName length: 64];
|
||||
[bytes appendBytes: &stStandardDate length: 16];
|
||||
[bytes appendBytes: &lStandardBias length: 4];
|
||||
[bytes appendBytes: daylightName length: 64];
|
||||
[bytes appendBytes: &stDaylightDate length: 16];
|
||||
[bytes appendBytes: &lDaylightBias length: 4];
|
||||
|
||||
return [bytes activeSyncRepresentationInContext: context];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#ifndef __ICALTODOACTIVESYNC_H__
|
||||
#define __ICALTODOACTIVESYNC_H__
|
||||
|
||||
#import <NGCards/iCalToDo.h>
|
||||
|
||||
@class NSString;
|
||||
@class WOContext;
|
||||
|
||||
@interface iCalToDo (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context;
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,256 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2014, Inverse inc.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the Inverse inc. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
#import "iCalToDo+ActiveSync.h"
|
||||
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import <NGExtensions/NSString+misc.h>
|
||||
#import <NGObjWeb/WOContext.h>
|
||||
#import <NGObjWeb/WOContext+SoObjects.h>
|
||||
#import <NGObjWeb/WORequest.h>
|
||||
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserDefaults.h>
|
||||
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalDateTime.h>
|
||||
#import <NGCards/iCalTimeZone.h>
|
||||
|
||||
#include "NSDate+ActiveSync.h"
|
||||
#include "NSString+ActiveSync.h"
|
||||
|
||||
|
||||
@implementation iCalToDo (ActiveSync)
|
||||
|
||||
- (NSString *) activeSyncRepresentationInContext: (WOContext *) context
|
||||
{
|
||||
NSMutableString *s;
|
||||
NSArray *categories;
|
||||
id o;
|
||||
|
||||
int v, i;
|
||||
|
||||
s = [NSMutableString string];
|
||||
|
||||
// Complete
|
||||
[s appendFormat: @"<Complete xmlns=\"Tasks:\">%d</Complete>", [[self status] isEqualToString: @"COMPLETED"] ? 1 : 0];
|
||||
|
||||
// DateCompleted
|
||||
if ((o = [self completed]))
|
||||
[s appendFormat: @"<DateCompleted xmlns=\"Tasks:\">%@</DateCompleted>", [o activeSyncRepresentationInContext: context]];
|
||||
|
||||
// Start date
|
||||
if ((o = [self startDate]))
|
||||
{
|
||||
[s appendFormat: @"<StartDate xmlns=\"Tasks:\">%@</StartDate>", [o activeSyncRepresentationInContext: context]];
|
||||
[s appendFormat: @"<UTCStartDate xmlns=\"Tasks:\">%@</UTCStartDate>", [o activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
|
||||
// Due date
|
||||
if ((o = [self due]))
|
||||
{
|
||||
[s appendFormat: @"<DueDate xmlns=\"Tasks:\">%@</DueDate>", [o activeSyncRepresentationInContext: context]];
|
||||
[s appendFormat: @"<UTCDueDate xmlns=\"Tasks:\">%@</UTCDueDate>", [o activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
|
||||
// Importance
|
||||
o = [self priority];
|
||||
if ([o isEqualToString: @"9"])
|
||||
v = 0;
|
||||
else if ([o isEqualToString: @"1"])
|
||||
v = 2;
|
||||
else
|
||||
v = 1;
|
||||
[s appendFormat: @"<Importance xmlns=\"Tasks:\">%d</Importance>", v];
|
||||
|
||||
// Reminder - FIXME
|
||||
[s appendFormat: @"<ReminderSet xmlns=\"Tasks:\">%d</ReminderSet>", 0];
|
||||
|
||||
// Sensitivity
|
||||
if ([[self accessClass] isEqualToString: @"PRIVATE"])
|
||||
v = 2;
|
||||
else if ([[self accessClass] isEqualToString: @"CONFIDENTIAL"])
|
||||
v = 3;
|
||||
else
|
||||
v = 0;
|
||||
|
||||
[s appendFormat: @"<Sensitivity xmlns=\"Tasks:\">%d</Sensitivity>", v];
|
||||
|
||||
categories = [self categories];
|
||||
|
||||
if ([categories count])
|
||||
{
|
||||
[s appendFormat: @"<Categories xmlns=\"Tasks:\">"];
|
||||
for (i = 0; i < [categories count]; i++)
|
||||
{
|
||||
[s appendFormat: @"<Category xmlns=\"Tasks:\">%@</Category>", [[categories objectAtIndex: i] activeSyncRepresentationInContext: context]];
|
||||
}
|
||||
[s appendFormat: @"</Categories>"];
|
||||
}
|
||||
|
||||
// Subject
|
||||
o = [self summary];
|
||||
if ([o length])
|
||||
[s appendFormat: @"<Subject xmlns=\"Tasks:\">%@</Subject>", [[self summary] activeSyncRepresentationInContext: context]];
|
||||
|
||||
if ((o = [self comment]))
|
||||
{
|
||||
// It is very important here to NOT set <Truncated>0</Truncated> in the response,
|
||||
// otherwise it'll prevent WP8 phones from sync'ing. See #3028 for details.
|
||||
o = [o activeSyncRepresentationInContext: context];
|
||||
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
[s appendFormat: @"<Body xmlns=\"Tasks:\">%@</Body>", o];
|
||||
[s appendString: @"<BodyTruncated xmlns=\"Tasks:\">0</BodyTruncated>"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
|
||||
[s appendFormat: @"<Type>%d</Type>", 1];
|
||||
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];
|
||||
[s appendFormat: @"<Data>%@</Data>", o];
|
||||
[s appendString: @"</Body>"];
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
- (void) takeActiveSyncValues: (NSDictionary *) theValues
|
||||
inContext: (WOContext *) context
|
||||
{
|
||||
NSTimeZone *userTimeZone;
|
||||
iCalTimeZone *tz;
|
||||
id o;
|
||||
|
||||
userTimeZone = [[[context activeUser] userDefaults] timeZone];
|
||||
tz = [iCalTimeZone timeZoneForName: [userTimeZone name]];
|
||||
[(iCalCalendar *) parent addTimeZone: tz];
|
||||
|
||||
// FIXME: merge with iCalEvent
|
||||
if ((o = [theValues objectForKey: @"Subject"]))
|
||||
[self setSummary: o];
|
||||
|
||||
// FIXME: merge with iCalEvent
|
||||
if ([[[context request] headerForKey: @"MS-ASProtocolVersion"] isEqualToString: @"2.5"])
|
||||
{
|
||||
if ((o = [theValues objectForKey: @"Body"]))
|
||||
[self setComment: o];
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((o = [[theValues objectForKey: @"Body"] objectForKey: @"Data"]))
|
||||
[self setComment: o];
|
||||
}
|
||||
|
||||
if ([[theValues objectForKey: @"Complete"] intValue] &&
|
||||
((o = [theValues objectForKey: @"DateCompleted"])) )
|
||||
{
|
||||
iCalDateTime *completed;
|
||||
|
||||
o = [o calendarDate];
|
||||
completed = (iCalDateTime *) [self uniqueChildWithTag: @"completed"];
|
||||
[completed setDate: o];
|
||||
[self setStatus: @"COMPLETED"];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self setStatus: @"IN-PROCESS"];
|
||||
[self setCompleted: nil];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"DueDate"]))
|
||||
{
|
||||
iCalDateTime *due;
|
||||
|
||||
o = [o calendarDate];
|
||||
due = (iCalDateTime *) [self uniqueChildWithTag: @"due"];
|
||||
[due setTimeZone: tz];
|
||||
[due setDateTime: o];
|
||||
}
|
||||
|
||||
if ((o = [theValues objectForKey: @"StartDate"]))
|
||||
{
|
||||
iCalDateTime *due;
|
||||
|
||||
o = [o calendarDate];
|
||||
due = (iCalDateTime *) [self uniqueChildWithTag: @"dtstart"];
|
||||
[due setTimeZone: tz];
|
||||
[due setDateTime: o];
|
||||
}
|
||||
|
||||
// 2 == high, 1 == normal, 0 == low
|
||||
if ((o = [theValues objectForKey: @"Importance"]))
|
||||
{
|
||||
if ([o intValue] == 2)
|
||||
[self setPriority: @"1"];
|
||||
else if ([o intValue] == 1)
|
||||
[self setPriority: @"5"];
|
||||
else
|
||||
[self setPriority: @"9"];
|
||||
}
|
||||
|
||||
//
|
||||
// 0- normal, 1- personal, 2- private and 3-confidential
|
||||
//
|
||||
if ((o = [theValues objectForKey: @"Sensitivity"]))
|
||||
{
|
||||
switch ([o intValue])
|
||||
{
|
||||
case 2:
|
||||
[self setAccessClass: @"PRIVATE"];
|
||||
break;
|
||||
case 3:
|
||||
[self setAccessClass: @"CONFIDENTIAL"];
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
default:
|
||||
[self setAccessClass: @"PUBLIC"];
|
||||
}
|
||||
}
|
||||
|
||||
// Categories
|
||||
if ((o = [theValues objectForKey: @"Categories"]) && [o length])
|
||||
[self setCategories: o];
|
||||
|
||||
if ((o = [theValues objectForKey: @"ReminderTime"]))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
requires = ( MAIN, Appointments, Contacts, Mailer );
|
||||
}
|
||||
@@ -28,13 +28,8 @@
|
||||
ProxyPass /SOGo http://127.0.0.1:20000/SOGo interpolate
|
||||
ProxyPass / http://127.0.0.1:20000/SOGo/dav/ interpolate
|
||||
<Location />
|
||||
<IfVersion < 2.4>
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</IfVersion>
|
||||
<IfVersion >= 2.4>
|
||||
Require all granted
|
||||
</IfVersion>
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Location>
|
||||
|
||||
<Proxy http://127.0.0.1:20000>
|
||||
|
||||
+10
-30
@@ -2,17 +2,13 @@ Alias /SOGo.woa/WebServerResources/ \
|
||||
/usr/lib/GNUstep/SOGo/WebServerResources/
|
||||
Alias /SOGo/WebServerResources/ \
|
||||
/usr/lib/GNUstep/SOGo/WebServerResources/
|
||||
AliasMatch /SOGo/so/ControlPanel/Products/(.*)/Resources/(.*) \
|
||||
/usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2
|
||||
|
||||
<Directory /usr/lib/GNUstep/SOGo/>
|
||||
AllowOverride None
|
||||
|
||||
<IfVersion < 2.4>
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</IfVersion>
|
||||
<IfVersion >= 2.4>
|
||||
Require all granted
|
||||
</IfVersion>
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
|
||||
# Explicitly allow caching of static content to avoid browser specific behavior.
|
||||
# A resource's URL MUST change in order to have the client load the new version.
|
||||
@@ -22,27 +18,20 @@ Alias /SOGo/WebServerResources/ \
|
||||
</IfModule>
|
||||
</Directory>
|
||||
|
||||
<LocationMatch "^/SOGo/so/ControlPanel/Products/.*UI/Resources/.*\.(jpg|png|gif|css|js)">
|
||||
SetHandler default-handler
|
||||
</LocationMatch>
|
||||
|
||||
## Uncomment the following to enable proxy-side authentication, you will then
|
||||
## need to set the "SOGoTrustProxyAuthentication" SOGo user default to YES and
|
||||
## adjust the "x-webobjects-remote-user" proxy header in the "Proxy" section
|
||||
## below.
|
||||
#
|
||||
## For full proxy-side authentication:
|
||||
#<Location /SOGo>
|
||||
# AuthType XXX
|
||||
# Require valid-user
|
||||
# SetEnv proxy-nokeepalive 1
|
||||
# Allow from all
|
||||
#</Location>
|
||||
#
|
||||
## For proxy-side authentication only for CardDAV and GroupDAV from external
|
||||
## clients:
|
||||
#<Location /SOGo/dav>
|
||||
# AuthType XXX
|
||||
# Require valid-user
|
||||
# SetEnv proxy-nokeepalive 1
|
||||
# Allow from all
|
||||
#</Location>
|
||||
|
||||
ProxyRequests Off
|
||||
SetEnv proxy-nokeepalive 1
|
||||
@@ -59,14 +48,6 @@ ProxyPreserveHost On
|
||||
|
||||
ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
|
||||
|
||||
# Enable to use Microsoft ActiveSync support
|
||||
# Note that you MUST have many sogod workers to use ActiveSync.
|
||||
# See the SOGo Installation and Configuration guide for more details.
|
||||
#
|
||||
#ProxyPass /Microsoft-Server-ActiveSync \
|
||||
# http://127.0.0.1:20000/SOGo/Microsoft-Server-ActiveSync \
|
||||
# retry=60 connectiontimeout=5 timeout=360
|
||||
|
||||
<Proxy http://127.0.0.1:20000/SOGo>
|
||||
## adjust the following to your configuration
|
||||
RequestHeader set "x-webobjects-server-port" "443"
|
||||
@@ -75,8 +56,7 @@ ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
|
||||
|
||||
## When using proxy-side autentication, you need to uncomment and
|
||||
## adjust the following line:
|
||||
RequestHeader unset "x-webobjects-remote-user"
|
||||
# RequestHeader set "x-webobjects-remote-user" "%{REMOTE_USER}e" env=REMOTE_USER
|
||||
# RequestHeader set "x-webobjects-remote-user" "%{REMOTE_USER}e"
|
||||
|
||||
RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"
|
||||
|
||||
@@ -86,7 +66,7 @@ ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0
|
||||
Allow from all
|
||||
</Proxy>
|
||||
|
||||
# For Apple autoconfiguration
|
||||
# For apple autoconfiguration
|
||||
<IfModule rewrite_module>
|
||||
RewriteEngine On
|
||||
RewriteRule ^/.well-known/caldav/?$ /SOGo/dav [R=301]
|
||||
|
||||
+5655
File diff suppressed because it is too large.
Load diff
@@ -1,8 +0,0 @@
|
||||
all: $(patsubst %.asciidoc,%.pdf,$(wildcard *.asciidoc))
|
||||
|
||||
%.pdf : %.asciidoc
|
||||
asciidoc -a docinfo1 -b docbook -d book -o $<.docbook $<
|
||||
fop -c fonts/fop-config.xml -xsl docbook/xsl/sogo-fo.xsl -xml $<.docbook -pdf $@
|
||||
|
||||
clean:
|
||||
rm *.asciidoc.docbook *.pdf
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,157 +0,0 @@
|
||||
https://wiki.inverse.ca/focus/SOGo/CodingStyle
|
||||
https://wiki.inverse.ca/focus/SOGo/D%C3%A9veloppement
|
||||
https://wiki.inverse.ca/focus/PacketFence/Devel/BestPractices
|
||||
|
||||
UI and UX
|
||||
---------
|
||||
|
||||
* http://www.google.com/design/spec/material-design/
|
||||
* http://goodui.org/
|
||||
* Try Repeating Your Primary Action instead of showing it just once.
|
||||
* Try Distinct Clickable/Selected Styles instead of blurring them.
|
||||
* Try Undos instead of prompting for confirmation.
|
||||
* Try More Contrast instead of similarity.
|
||||
* Try Exposing Options instead of hiding them.
|
||||
* Try Showing State instead of being state agnostic.
|
||||
* Try Direct Manipulation instead of contextless menus.
|
||||
* Try Exposing Fields instead of creating extra pages.
|
||||
* Try Transitions instead of showing changes instantly.
|
||||
* Try Fewer Borders instead of wasting attention.
|
||||
* Try Designing For Zero Data instead of just data heavy cases.
|
||||
* Try Consistency instead of making people relearn.
|
||||
* Try Conventions instead of reinventing the wheel.
|
||||
* Try Visual Hierarchy instead of dullness.
|
||||
* Try Grouping Related Items instead of disordering.
|
||||
* Try Inline Validation instead of delaying errors.
|
||||
* Try Forgiving Inputs instead of being strict with data.
|
||||
* Try Bigger Click Areas instead of tiny ones.
|
||||
* Try Faster Load Times instead of making people wait.
|
||||
* Try Keyboard Shortcuts instead of buttons only.
|
||||
* Try Upfront Progress instead of starting with a blank.
|
||||
* Try Softer Prompts instead of modal windows.
|
||||
* Try Multifunctional Controls instead of more parts.
|
||||
* Try Icon Labels instead of opening for interpretation.
|
||||
* http://designmodo.com/create-style-guides/
|
||||
* http://uxmyths.com/
|
||||
|
||||
Frameworks & Tools
|
||||
------------------
|
||||
|
||||
GNUstep
|
||||
~~~~~~~
|
||||
|
||||
SOPE
|
||||
~~~~
|
||||
|
||||
AngularJS
|
||||
~~~~~~~~~
|
||||
|
||||
* https://angularjs.org/
|
||||
* http://angular-ui.github.io/ui-router/
|
||||
* https://www.airpair.com/angularjs/posts/angularjs-tutorial
|
||||
|
||||
Angular Material
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
* https://material.angularjs.org/
|
||||
|
||||
Lo-Dash
|
||||
~~~~~~~
|
||||
|
||||
* http://lodash.com/
|
||||
* http://underscorejs.org/
|
||||
|
||||
Code Style
|
||||
----------
|
||||
|
||||
Objective-C
|
||||
~~~~~~~~~~~
|
||||
|
||||
* To document the Web APIs, we follow the http://apidocjs.com/[APIDOC] standards.
|
||||
|
||||
apidoc -f ".*\\.m" -i UI -o Documentation/JSON-API
|
||||
|
||||
HTML
|
||||
~~~~
|
||||
|
||||
* Localize your strings:
|
||||
|
||||
<var:string label:value="I'm localized!"/>
|
||||
|
||||
* Localize your attributes:
|
||||
|
||||
<input type="text" label:placeholder="I'm localized!"/>
|
||||
|
||||
* Reuse existing localized strings as much as possible. Otherwise don't forget to update the English Localizable.strings file of the appropriate module.
|
||||
|
||||
JavaScript
|
||||
~~~~~~~~~~
|
||||
|
||||
* http://eslint.org/
|
||||
* https://github.com/toddmotto/angularjs-styleguide
|
||||
* https://github.com/angular/material/blob/master/docs/guides/CODING.md
|
||||
|
||||
* We conform to https://github.com/airbnb/javascript[Airbnb coding standards]. Use https://github.com/jscs-dev/node-jscs[jscs] with the 'airbnb' preset to validate your code style:
|
||||
|
||||
jscs -p airbnb *.js
|
||||
|
||||
* For documentation, we follow the http://usejsdoc.org/[JSDoc3] standards:
|
||||
|
||||
jsdoc UI/WebServerResources/js/{Appointments,Common,Contacts,Mailer}/*.js -d Documentation/JavaScript-API
|
||||
|
||||
Models (facades)
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
////
|
||||
http://trochette.github.io/Angular-Design-Patterns-Best-Practices/
|
||||
////
|
||||
* Move business logic into models and share them.
|
||||
* Keep it simple, separate server interaction and error handling from the model. That way model only handle data processing and code is easier to maintain.
|
||||
|
||||
SASS/CSS
|
||||
~~~~~~~~
|
||||
|
||||
* http://componentcss.com/
|
||||
* https://github.com/styleguide/css
|
||||
* https://smacss.com/
|
||||
|
||||
* For documentation, we follow http://sassdoc.com/[SassDoc] annotations.
|
||||
* We need the SASS files of Angular Material to build our CSS. The git repository of Angular Material is included as a submodule of SOGo:
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
* FlexBox compatibility http://caniuse.com/#feat=flexbox
|
||||
|
||||
Fonts
|
||||
^^^^^
|
||||
|
||||
* We build a custom icons font using the online app https://icomoon.io/app/#/select[icomoon].
|
||||
* http://www.carrois.com/fira-4-0/
|
||||
* Material Design Iconic Font http://zavoloklom.github.io/material-design-iconic-font/icons.html
|
||||
|
||||
Version Control
|
||||
---------------
|
||||
|
||||
* https://devcharm.com/articles/46/improve-your-git-workflow/
|
||||
* Each commit should cover only one thing;
|
||||
* Begin the commit message with a single short (less than 50 characters) line summarizing the change, followed by a blank line and then a more thorough description;
|
||||
* When fixing a bug, commit to the devel branch as well as the maintenance branch of the latest release version (named maintenance/x.y). When a ticket is associated to the bug, add to the description a line saying *Fixes #1234*.
|
||||
* `git pull` may introduce http://stackoverflow.com/questions/15316601/in-what-cases-could-git-pull-be-harmful[inconsistencies and problems]. Replace it with the following alias:
|
||||
|
||||
git config --global alias.up '!git remote update -p; git merge --ff-only @{u}'
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
* https://github.com/angular/protractor
|
||||
* http://karma-runner.github.io/
|
||||
|
||||
JSON API
|
||||
~~~~~~~~
|
||||
|
||||
One practical way to test the JSON API is to use `curl`. To do so, you need to enable `SOGoTrustProxyAuthentication` and configure HTTP authentifcation in Apache. You can pipe the result to [jq](http://stedolan.github.io/jq/) to nicely format and filter the output:
|
||||
|
||||
curl -u username:password http://localhost/SOGo/so/username/Calendar/calendarslist | jq '.'
|
||||
|
||||
curl -u username:password -H 'Content-Type: application/json' -d '{}' http://localhost/SOGo/so/francis/Calendar/personal/71B6-54904400-1-7C308500.ics/save
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,330 +0,0 @@
|
||||
Mobile Devices Configuration Guide
|
||||
==================================
|
||||
|
||||
////
|
||||
|
||||
This file is part of the SOGo project.
|
||||
|
||||
See SOGo Mobile Devices Configuration-docinfo.xml for authors,
|
||||
copyright and license information.
|
||||
|
||||
////
|
||||
|
||||
include::includes/global-attributes.asciidoc[]
|
||||
|
||||
About this Guide
|
||||
----------------
|
||||
|
||||
This guide will walk you through the installation and configuration of
|
||||
popular SyncML clients to be used with the SOGo solution.
|
||||
|
||||
This guide also include instructions for configuring Apple iPhone OS
|
||||
devices (iPhone, iPod touch, and iPad).
|
||||
|
||||
The instructions are based on version {release_version} of SOGo.
|
||||
|
||||
The latest version of this guide is available at
|
||||
http://www.sogo.nu/downloads/documentation.html.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
SOGo is a free and modern scalable groupware server. It offers shared
|
||||
calendars, address books, and emails through your favourite Web browser
|
||||
and by using a native client such as Mozilla Thunderbird and Lightning.
|
||||
|
||||
SOGo is standard-compliant. It supports CalDAV, CardDAV, GroupDAV, iMIP
|
||||
and iTIP and reuses existing IMAP, SMTP and database servers - making
|
||||
the solution easy to deploy and interoperable with many applications.
|
||||
|
||||
SOGo features:
|
||||
|
||||
* Scalable architecture suitable for deployments from dozen to many
|
||||
thousand users
|
||||
* Rich Web-based interface that shares the look and feel, the features
|
||||
and the data of Mozilla Thunderbird and Lightning
|
||||
* Improved integration with Mozilla Thunderbird and Lighthing by using
|
||||
the SOGo Connector and the SOGo Integrator
|
||||
* Two-way synchronization support with any Microsoft ActiveSync-capable
|
||||
device, or Outlook 2013
|
||||
|
||||
SOGo is developed by a community of developers located mainly in North
|
||||
America and Europe. More information can be found on
|
||||
http://www.sogo.nu/.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
This section will guide you through the installation of popular SyncML
|
||||
clients on various devices.
|
||||
|
||||
Funambol SyncML Client
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The recommended SyncML client for BlackBerry, Apple iPhone (for
|
||||
contacts), mobile devices based on Microsoft Windows Mobile Smartphone
|
||||
or Windows Mobile PocketPC, is the one provided directly by Funambol,
|
||||
which is free and open source.
|
||||
|
||||
For Microsoft Window Mobile, you must identify which kind of device you
|
||||
have ("Smartphone" vs. "PocketPC").
|
||||
|
||||
Once you've identified what kind of device you have, download the
|
||||
appropriate client from:
|
||||
|
||||
http://www.funambol.com/opensource/downloads.php
|
||||
|
||||
The version 8.5 GA or later is required.
|
||||
|
||||
NextHaus SyncJe
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
For BlackBerry and Apple iPhone devices, you can also use the
|
||||
SyncJe SyncML client from NextHaus (http://www.nexthaus.com/). This
|
||||
client allows one to synchronize contacts, event and tasks with SOGo.
|
||||
|
||||
The version 2.43 or later is required. For BlackBerry 7XXX devices, the
|
||||
required version is 2.25 but isn't officially supported. You can install
|
||||
SyncJe on your BlackBerry device, over the air, by opening the following
|
||||
link from your BlackBerry device:
|
||||
|
||||
http://www.nexthaus.com/bb/syncjebb.jad
|
||||
|
||||
This will download and install the application on your mobile device.
|
||||
It's important to use the Web browser application and not the WAP
|
||||
browser to perform this operation. Once installed, restart the device.
|
||||
This procedure can also be used to update the SyncJe application. Note
|
||||
that an update of SyncJe will not affect the state of previous
|
||||
synchronizations. It's not necessary to perform a "slow sync" after an
|
||||
update of SyncJe.
|
||||
|
||||
Synthesis SyncML Client
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Synthesis (http://www.synthesis.ch/) company provides a SyncML
|
||||
client for Palm OS-based devices.
|
||||
|
||||
"Over The Air" synchronization is possible, as well as synchronization
|
||||
through a cradle. For the latter, you must install Softick PPP using the
|
||||
Palm Desktop software. The version 3.01 or later is required and you can
|
||||
download it from http://www.softick.com/ppp/. Once installed, the
|
||||
desktop computer must be restarted.
|
||||
|
||||
Once completed, you must download the Synthesis client for Palm OS. The
|
||||
version 3.0.2.9 or later is required. Either the standard or the
|
||||
professional version can be used.
|
||||
|
||||
Once downloaded, uncompress the archive and install the `.prc` file on
|
||||
your Palm OS-based device. After, you should see a "SyncML" icon on your
|
||||
device.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
In this section, you'll learn how to configure the popular SyncML
|
||||
clients in order to fully synchronize your mobile device with SOGo.
|
||||
|
||||
Instructions for Apple iPhone OS based devices are also included. Note
|
||||
that those devices do not require a SyncML client for synchronizing
|
||||
calendars.
|
||||
|
||||
Funambol SyncML Client
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Once the Funambol SyncML client is installed, start the application from
|
||||
your mobile device to configure it using the following steps:
|
||||
|
||||
From the _Tools_ menu, choose _Options..._:
|
||||
|
||||
* Specify the _Location_. If your SOGo server is `sogo.domain.com`, the
|
||||
location should be `http://sogo.domain.com/funambol/ds`.
|
||||
* Specify your username and password
|
||||
* Check the _Contacts_ check box and click on the _Details_ button.
|
||||
The synchronization type is _two-way_ and the _Remote name_ is
|
||||
`sogo-card`. The data format is vCard.
|
||||
* Check the _Calendar_ check box and click on the _Details_ button. The
|
||||
synchronization type is _two-way_ and the _Remote name_ is `sogo-cal`.
|
||||
The data format is vCalendar.
|
||||
* Check the _Tasks_ check box and click on the _Details_ button. The
|
||||
synchronization type is _two-way_ and the _Remote name_ is
|
||||
`sogo-todo`. The data format is SIF.
|
||||
* Save the preferences.
|
||||
|
||||
To prevent the BlackBerry to automatically add a new event in the
|
||||
calendar when an invitation is received by email (IMIP message) on the
|
||||
BlackBerry device, you should delete the CICAL service from the Service
|
||||
Book. To do so, proceed with the following steps:
|
||||
|
||||
From the _Options_ menu:
|
||||
|
||||
* Choose _Advanced Options_
|
||||
* Choose _Service Book_
|
||||
* Identify the line that mentions the email address of the BlackBerry
|
||||
user followed by the `[CICAL]` string. For example, `user@domain.com
|
||||
[CICAL]`.
|
||||
* Delete this entry.
|
||||
|
||||
Once completed, you must restart the device by removing its battery for
|
||||
a couple of seconds. If you ever want to reactivate the CICAL service,
|
||||
follow those instructions:
|
||||
|
||||
http://support.appriver.com/KB/a205/how-to-resend-service-books-on-blackberry.aspx
|
||||
|
||||
Once complete, the client is ready for an initial synchronization.
|
||||
|
||||
Ideally, you should *delete* all data from the mobile device before the
|
||||
initial synchronization. To do so:
|
||||
|
||||
* From the _Tools_ menu, choose _Recover..._
|
||||
* Choose _Replace with data from server_
|
||||
* Check the _Contacts_, _Calendar_ and _Tasks_ check boxes
|
||||
|
||||
Finally, click on the _Sync All_ button to proceed with the
|
||||
synchronization.
|
||||
|
||||
NextHaus SyncJe
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Once NextHaus SyncJe is installed, proceed with the following steps,
|
||||
from your BlackBerry device, to configure it:
|
||||
|
||||
* Open the _SyncJe Client_
|
||||
|
||||
From the _Settings_ menu:
|
||||
|
||||
* Specify the _Server URL_. If your SOGo server is `sogo.domain.com`,
|
||||
the URL should be `http://sogo.domain.com/funambol/ds`.
|
||||
* Specify your user name and password
|
||||
* Check the _Contacts_ check box and specify `sogo-card` as the
|
||||
_Foldername_
|
||||
* Check the _Calendar_ check box and specify `sogo-cal` as the
|
||||
_Foldername_
|
||||
* Check the _ToDo_ check box and specify `sogo-todo` as the _Foldername_
|
||||
* Check the _Auto Sync_ check box if you wish to automatically
|
||||
synchronize contacts, events and tasks at a predefined time interval
|
||||
* Do *not* check the _Sync events between_ check box
|
||||
* Check the _Skip saving attendees_ - this will prevent the BlackBerry
|
||||
device from sending emails to meeting participants for events
|
||||
downloaded from the SOGo server
|
||||
* Check the _BIS_ check box (for _BlackBerry Internet Services_)
|
||||
* Leave the other fields to the their default value
|
||||
* Then choose _Save_ from the menu to save the preferences
|
||||
|
||||
To prevent the BlackBerry to automatically add a new event in the
|
||||
calendar when an invitation is received by email (IMIP message) on the
|
||||
BlackBerry device, you should delete the CICAL service from the Service
|
||||
Book. To do so, proceed with the following steps:
|
||||
|
||||
From the _Options_ menu:
|
||||
|
||||
* Choose _Advanced Options_
|
||||
* Choose _Service Book_
|
||||
* Identify the line that mentions the email address of the BlackBerry
|
||||
user followed by the `[CICAL]` string. For example, `user@domain.com
|
||||
[CICAL]`.
|
||||
* Delete this entry
|
||||
|
||||
Once completed, you must restart the device by removing its battery for
|
||||
a couple of seconds. If you ever want to reactivate the CICAL service,
|
||||
follow those instructions:
|
||||
|
||||
http://support.appriver.com/KB/a205/how-to-resend-service-books-on-blackberry.aspx
|
||||
|
||||
Once done, you're now ready for your first synchronization.
|
||||
|
||||
Ideally, you must delete all data on the BlackBerry before proceeding
|
||||
with the initial synchronization. To do so, proceed with the following
|
||||
steps:
|
||||
|
||||
* Open the _SyncJe Client_
|
||||
|
||||
From the _Settings_ menu:
|
||||
|
||||
* Choose the _Clear databases_ option
|
||||
* Respond _Yes_ to all questions. This will delete all contacts, events
|
||||
and tasks from your BlackBerry device.
|
||||
* Go back in the previous menu
|
||||
* Choose the _Force Slow Sync_ option
|
||||
* Choose the _Start Sync_ option to start the synchronization. This
|
||||
could take a few minutes if you have many contacts, events or tasks.
|
||||
Subsequent synchronizations should be much faster.
|
||||
|
||||
After the initial _Slow Sync_, you can simply chose the _Start Sync_
|
||||
option if you do a manual synchronization to synchronize all changes.
|
||||
|
||||
Synthesis SyncML Client
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Once the Synthesis SyncML client is installed, proceed with the
|
||||
following steps to configure it:
|
||||
|
||||
* Open the _Synthesis SyncML Standard Edition_ application
|
||||
|
||||
From the _Settings..._ menu:
|
||||
|
||||
* Specify the _Server URL_. If your SOGo server is `sogo.domain.com`,
|
||||
the URL should be `http://sogo.domain.com/funambol/ds`.
|
||||
* Specify your user name and password
|
||||
* Check the _Contacts_, _Events_ and _Task_ check boxes
|
||||
* Click on the _more..._ button
|
||||
* For the _Contacts_, choose _reload device_ and specify `sogo-card` as
|
||||
the _Server Path_.
|
||||
* For the _Events_, choose _reload device_ and specify `sogo-cal` as
|
||||
the _Server Path_. Do *not* check the _Only from..._ check box.
|
||||
* For the _Tasks_, choose _reload device_ and specify `sogo-todo` as
|
||||
the _Server Path_.
|
||||
* Once completed, click on the _Done_ button
|
||||
|
||||
The _reload device_ value will *delete* all entries on the device during
|
||||
the initial synchronization and obtain contacts, events and tasks from
|
||||
the server. If you do not want to delete everything from the device,
|
||||
please choose _normal_ instead of _reload device_.
|
||||
|
||||
Once ready, click on the _Start_ button to proceed with the initial
|
||||
synchronization.
|
||||
|
||||
During the initial synchronization, the Palm device will ask you how to
|
||||
connect to the desktop system. From the Palm device, choose _Windows
|
||||
RAS_ without specifying an user name or a password. This will allow the
|
||||
Palm device to establish a PPP connection between itself and Softick PPP
|
||||
and then communicate using its TCP/IP stack to the Funambol server.
|
||||
|
||||
Apple iOS — Calendars
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Starting from iOS 3, Apple has added CalDAV support to the calendar
|
||||
application included in the iPhone/iPod/iPad.
|
||||
|
||||
To add a CalDAV account, follow those instructions:
|
||||
|
||||
* From the _Settings_ menu, choose _Mail, Contacts, Calendars_
|
||||
* Choose _Add Account..._
|
||||
* Choose _Other_
|
||||
* Choose _Add CalDAV Account_
|
||||
* Specify the _Server_, the URL should be
|
||||
`http://sogo.domain.com/SOGo/dav/<username>`
|
||||
|
||||
On iOS 3.1.2 and later, you must also specify the range of events you
|
||||
want to have.
|
||||
|
||||
* From the _Settings_ menu, choose _Mail, Contacts, Calendars_
|
||||
* From the _Sync_ menu, choose _All Events_
|
||||
|
||||
Note that other options (_Events 2 Weeks Back_, etc.) do not work right
|
||||
now.
|
||||
|
||||
Apple iOS — Contacts
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you want to synchronize contacts with your Apple mobile device, use
|
||||
the native address book application with SOGo using the CardDAV
|
||||
protocol. To configure the address book application so it works with
|
||||
SOGo, create a new CardDAV account and specify your server name. In
|
||||
the _Advanced Settings_, set the port to `8800`.
|
||||
|
||||
On iOS prior to version 4, you must install the Funambol client and
|
||||
configure the `sogo-card` source.
|
||||
|
||||
include::includes/additional-info.asciidoc[]
|
||||
|
||||
include::includes/commercial-support.asciidoc[]
|
||||
@@ -1,358 +0,0 @@
|
||||
Mozilla Thunderbird Configuration Guide
|
||||
=======================================
|
||||
|
||||
////
|
||||
|
||||
This file is part of the SOGo project.
|
||||
|
||||
See SOGo Mozilla Thunderbird Configuration Guide-docinfo.xml for
|
||||
authors, copyright and license information.
|
||||
|
||||
////
|
||||
|
||||
include::includes/global-attributes.asciidoc[]
|
||||
|
||||
About this Guide
|
||||
----------------
|
||||
|
||||
This guide will walk you through the installation and configuration of
|
||||
Mozilla Thunderbird and its associated extensions so it can be used with
|
||||
the SOGo solution.
|
||||
|
||||
The instructions are based on version {release_version} of SOGo.
|
||||
|
||||
The latest version of this guide is available
|
||||
at http://www.sogo.nu/downloads/documentation.html.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
SOGo is a free and modern scalable groupware server. It offers shared
|
||||
calendars, address books, and emails through your favourite Web browser
|
||||
and by using a native client such as Mozilla Thunderbird and Lightning.
|
||||
|
||||
SOGo is standard-compliant. It supports CalDAV, CardDAV, GroupDAV, iMIP
|
||||
and iTIP and reuses existing IMAP, SMTP and database servers - making
|
||||
the solution easy to deploy and interoperable with many applications.
|
||||
|
||||
SOGo features:
|
||||
|
||||
* Scalable architecture suitable for deployments from dozen to many
|
||||
thousand users
|
||||
* Rich Web-based interface that shares the look and feel, the features
|
||||
and the data of Mozilla Thunderbird and Lightning
|
||||
* Improved integration with Mozilla Thunderbird and Lightning by using
|
||||
the SOGo Connector and the SOGo Integrator extensions
|
||||
* Two-way synchronization support with any Microsoft ActiveSync-capable
|
||||
device, or Outlook 2013
|
||||
|
||||
SOGo is developed by a community of developers located mainly in North
|
||||
America and Europe. More information can be found on
|
||||
http://www.sogo.nu/.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
This section will guide you through the installation of Thunderbird and
|
||||
its associated extensions.
|
||||
|
||||
Mozilla Thunderbird
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Mozilla Thunderbird is the official front end client of SOGo.
|
||||
|
||||
Mozilla Thunderbird version 2, 3.1, 10 ESR (Extended Support Release),
|
||||
17 ESR, 24 and 31 are supported and it is recommended to use version 31 of
|
||||
Thunderbird.
|
||||
|
||||
In order to download and install Mozilla Thunderbird, please visit:
|
||||
|
||||
https://www.mozilla.org/en-US/thunderbird/organizations/all-esr.html
|
||||
|
||||
Mozilla Lightning
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
When using version 24 or 31 of Thunderbird, you can use the latest version of
|
||||
Mozilla Lightning. Use the Add-ons manager of Thunderbird or visit:
|
||||
|
||||
https://addons.mozilla.org/en-US/thunderbird/addon/lightning/
|
||||
|
||||
When using version 17 ESR of Thunderbird, you can use Mozilla Lightning
|
||||
version 1.9.1. In order to download the extension, please visit:
|
||||
|
||||
https://addons.mozilla.org/en-US/thunderbird/addon/lightning/versions/1.9.1
|
||||
|
||||
For Thunderbird 2 and 3.1, you need the _Inverse Edition_of Mozilla
|
||||
Lightning. It provides back ported features, bug fixes and security
|
||||
fixes from the current development version of Mozilla Lightning. For
|
||||
Thunderbird 2, it is based on release version 0.9 of Lightning. For
|
||||
Thunderbird 3.1, it is based on 1.0b2.
|
||||
|
||||
In order to download and install Mozilla Lightning – Inverse Edition for
|
||||
Thunderbird 2 or 3.1, please visit:
|
||||
|
||||
http://www.sogo.nu/downloads/frontends.html
|
||||
|
||||
SOGo Connector and SOGo Integrator
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The SOGo Connector and Integrator extensions are provided to perfect the
|
||||
integration of Mozilla Thunderbird 2, 3.1, 10 ESR, 17 ESR, 24 and 31 with
|
||||
the SOGo groupware solution.
|
||||
|
||||
First of all, the SOGo Connector extension transforms Thunderbird into a
|
||||
full DAV client for groupware servers such as SOGo, eGroupware or
|
||||
Citadel. It does this by adding support for remote DAV address books and
|
||||
by adding features to be used along with the Lightning calendar
|
||||
extension.
|
||||
|
||||
Among supported features of the SOGo Connector extension, we have:
|
||||
|
||||
* Free / Busy URL field in the address book
|
||||
* Free / Busy functionality through HTTP
|
||||
* Event organizers
|
||||
* Synchronization of the address book using GroupDAV
|
||||
* CardDAV implementation for the address book
|
||||
* Support for WebDAV ACL
|
||||
|
||||
On the other hand, the SOGo Integrator extension transforms Thunderbird
|
||||
into a pure "heavy" client for SOGo. Whereas the SOGo Connector is meant
|
||||
for portability (horizontal integration), the SOGo Integrator makes use
|
||||
of the features and layout only available from SOGo (vertical
|
||||
integration).
|
||||
|
||||
Among the supported features of the SOGo Integrator extension, we have :
|
||||
|
||||
* Remote administration of folder subscriptions
|
||||
* Remote administration of folder access control lists (ACL)
|
||||
* Automatic replication of your local and subscribed folders
|
||||
* When correctly configured, it handles the propagation of updates to
|
||||
chosen extensions from a local update server
|
||||
* Automatic propagation of default settings
|
||||
|
||||
In order to download and install the SOGo Connector and Integrator
|
||||
extensions, please visit:
|
||||
|
||||
http://www.sogo.nu/downloads/frontends.html
|
||||
|
||||
Prior to installing the SOGo Integrator extension, you should read the
|
||||
following chapter – _SOGo Integrator Customization_.
|
||||
|
||||
SOGo Integrator Customization
|
||||
-----------------------------
|
||||
|
||||
In this section, you'll learn how to customize the SOGo Integrator
|
||||
extension so it can be used alongside your SOGo server.
|
||||
|
||||
Customization
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The customization steps described here involves understanding of XML and
|
||||
of text file edition. If you do not have those skills, it is recommended
|
||||
that you don't try to use this extension.
|
||||
|
||||
There are actually two steps in the configuration of a working
|
||||
environment for SOGo Integrator. First of all, the Integrator will use
|
||||
the same user name used to connect to the first email server configured
|
||||
in Thunderbird. It is a current limitation but it will fit nearly all
|
||||
configurations out there.
|
||||
|
||||
For testing purpose, you are strongly recommended to create and
|
||||
configure an additional user profile for Thunderbird. This is for two
|
||||
reasons. The first is because of the limitation mentioned above. The
|
||||
second is because the Integrator will synchronize your personal address
|
||||
book onto the SOGo server and then remove it so that only your personal
|
||||
address book on SOGo will be available. If you are not able to do that,
|
||||
you may want to make a copy of that address book beforehand.
|
||||
|
||||
The second part requires editing one file in the extension file sub tree
|
||||
to specify where the SOGo server is located. This is done by hand. In an
|
||||
enterprise environment, this step is only required once per release
|
||||
since the updates are expected to propagate automatically.
|
||||
|
||||
Uncompress (using a ZIP or jar tool) the SOGo Integrator XPI and locate
|
||||
the following file:
|
||||
|
||||
extensions.rdf
|
||||
|
||||
This file is used for locating the extension update server and the SOGo
|
||||
server, which we consider to be the same for the moment. There is a line
|
||||
starting with a "Seq" tag and with an attribute named "isi:updateURL".
|
||||
Replace the host part of that url with the SOGo server you want to
|
||||
connect to.
|
||||
|
||||
For example, one would replace:
|
||||
|
||||
<Seq about="http://inverse.ca/sogo-integrator/extensions" isi:updateURL="http://sogo-demo.inverse.ca/plugins/updates.php?plugin=%ITEM_ID%&version=%ITEM_VERSION%&platform=%PLATFORM%">
|
||||
|
||||
by:
|
||||
|
||||
<Seq about="http://inverse.ca/sogo-integrator/extensions" isi:updateURL="https://sogo.acme.com/plugins/updates.php?plugin=%ITEM_ID%&version=%ITEM_VERSION%&platform=%PLATFORM%">
|
||||
|
||||
if the SOGo server is accessible from the following URL:
|
||||
|
||||
https://sogo.acme.com/SOGo
|
||||
|
||||
Note that if you changed the `x-webobjects-server-url` configuration
|
||||
setting from your HTTP server configuration file for SOGo, the
|
||||
value *must* match the one you specify in `isi:updateURL` – even the
|
||||
port number.
|
||||
|
||||
Moreover, you *must* change the value of the
|
||||
`sogo-integrator.autocomplete.server.urlid` preference from
|
||||
`defaults/preferences/site.js` to match the identifier of your
|
||||
_SOGoUserSources_. This source will be used by Thunderbird for
|
||||
autocompletion.
|
||||
|
||||
Once you're done modifying the configuration file, save your changes and
|
||||
reconstruct the XPI file.
|
||||
|
||||
Now start Thunderbird and install your newly modified extension.
|
||||
|
||||
SOGo Update Server
|
||||
------------------
|
||||
|
||||
In this section, you will learn how to install and configure the SOGo
|
||||
Update Server.
|
||||
|
||||
The SOGo Update Server can be used to automatically install or uninstall
|
||||
Mozilla Thunderbird extensions, push user settings and more – all from a
|
||||
central place managed by system administrators.
|
||||
|
||||
Installation
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Installation is relatively straightforward. You need to make
|
||||
the `updates.php` script available through your HTTP server at the URL
|
||||
you've specified from the `extensions.rdf` file. The `updates.php`
|
||||
script can be found in the SOGo sources, under the `Scripts` directory.
|
||||
|
||||
The `updateLink` section of the XML payload returned to sogo-integrator
|
||||
is built dynamically using the `SCRIPT_URI` variable, which is only
|
||||
available when running with mod_rewrite. It should work out of the box
|
||||
as long as the script is placed in the same directory as the xpi files.
|
||||
|
||||
If it is not the case, then the link should be adjusted to fit the
|
||||
actual file layout:
|
||||
|
||||
<em:updateLink><?php echo dirname(getenv('SCRIPT_URI')) . '/relative/path/to/' . $plugin["filename"] ?></em:updateLink>
|
||||
|
||||
An http request similar to the following can be used to make sure that
|
||||
the generated link is correct:
|
||||
|
||||
http://sogo.host/path/to/updates.php?plugin=sogo-integrator@inverse.ca&version=0.00
|
||||
|
||||
Please refer to your HTTP server documentation for the installation and
|
||||
configuration of PHP.
|
||||
|
||||
Configuration
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
To configure the SOGo update server, you need to modify the
|
||||
`updates.php` script directly.
|
||||
|
||||
Adding an extension to be pushed automatically by the update server
|
||||
require you to modify the `$plugins` array from updates.php and also
|
||||
adjust accordingly SOGo Integrator's `extensions.rdf` file.
|
||||
|
||||
For example, to automatically install SOGo Connector, SOGo Integrator
|
||||
and Lightning, you would have:
|
||||
|
||||
----
|
||||
$plugins
|
||||
= array( "sogo-connector@inverse.ca"
|
||||
=> array( "application" => "thunderbird",
|
||||
"version" => "31.0.0",
|
||||
"filename" => "sogo-connector-31.0.0.xpi" ),
|
||||
"sogo-integrator@inverse.ca"
|
||||
=> array( "application" => "thunderbird",
|
||||
"version" => "31.0.0",
|
||||
"filename" => "sogo-integrator-31.0.0-sogo-demo.xpi" ),
|
||||
"{e2fda1a4-762b-4020-b5ad-a41df1933103}"
|
||||
=> array( "application" => "thunderbird",
|
||||
"version" => "3.3.1",
|
||||
"filename" => "lightning.xpi" ));
|
||||
----
|
||||
|
||||
The syntax is:
|
||||
|
||||
----
|
||||
"<extension ID>"
|
||||
=> array( "application" => "thunderbird",
|
||||
"version" => "<exact version found in the extension's install.rdf file>",
|
||||
"filename" => "<exact filename on the filesystem>" )
|
||||
----
|
||||
|
||||
The path of the filename, specified in the `filename` parameter, is
|
||||
relative to the location of the `updates.php` script. For extensions
|
||||
that are dependant on the architecture and operating system (Microsoft
|
||||
Windows, Apple Mac OS X, etc.), they can be placed in subdirectories
|
||||
relative again to the `updates.php` script (but the filename must be
|
||||
identical in all subdirectories). For exemple, for Mozilla Lightning, we
|
||||
could have:
|
||||
|
||||
----
|
||||
Darwin_x86-gcc3/lightning.xpi
|
||||
Linux_x86-gcc3/lightning.xpi
|
||||
Linux_x86_64-gcc3/lightning.xpi
|
||||
WINNT_x86-msvc/lightning.xpi
|
||||
----
|
||||
|
||||
If you eventually want to disable an extension, that is, without
|
||||
removing it from your users' computers, you can specify `disabled` as
|
||||
the version number.
|
||||
|
||||
Next is to modify the `extensions.rdf` file. Again, to automatically
|
||||
install SOGo Connector, SOGo Integrator and Lightning, you would have:
|
||||
|
||||
----
|
||||
<li>
|
||||
<Description
|
||||
em:id="{e2fda1a4-762b-4020-b5ad-a41df1933103}"
|
||||
em:name="Lightning"/>
|
||||
</li>
|
||||
<li>
|
||||
<Description
|
||||
em:id="sogo-integrator@inverse.ca"
|
||||
em:name="SOGo Integrator"/>
|
||||
</li>
|
||||
<li>
|
||||
<Description
|
||||
em:id="sogo-connector@inverse.ca"
|
||||
em:name="SOGo Connector"/>
|
||||
</li>
|
||||
----
|
||||
|
||||
Using SOGo Integrator, you can also push user-settings for any part of
|
||||
Thunderbird or its extensions. There are two kind of user-settings
|
||||
push:
|
||||
|
||||
* Settings that are pushed during the initial configuration of
|
||||
Thunderbird
|
||||
* Settings that are pushed upon every restart (ie., forced) of
|
||||
Thunderbird
|
||||
|
||||
Settings that pushed are pushed during initial configuration are
|
||||
controlled by the `./defaults/preferences/site.js` file from SOGo
|
||||
Integrator. Here is an example:
|
||||
|
||||
----
|
||||
pref("calendar.alarms.showmissed", false);
|
||||
pref("calendar.caldav.sched.enabled", true);
|
||||
----
|
||||
|
||||
Preferences that are forced upon every restart of Thunderbird are
|
||||
controlled from the `./chrome/content/general/custom-preferences.js`
|
||||
configuration file.
|
||||
|
||||
Here is an example:
|
||||
|
||||
----
|
||||
force_int_pref("changequote.replyformat.format", 0);
|
||||
force_bool_pref("changequote.headers.withcc", true);
|
||||
force_char_pref(“foo.bar”, “zot”);
|
||||
----
|
||||
|
||||
include::includes/additional-info.asciidoc[]
|
||||
|
||||
include::includes/commercial-support.asciidoc[]
|
||||
@@ -1,872 +0,0 @@
|
||||
Native Microsoft Outlook Configuration Guide
|
||||
============================================
|
||||
|
||||
////
|
||||
|
||||
This file is part of the SOGo project.
|
||||
|
||||
See SOGo Native Microsoft Outlook Configuration-docinfo.xml for
|
||||
authors, copyright and license information.
|
||||
|
||||
////
|
||||
|
||||
include::includes/global-attributes.asciidoc[]
|
||||
|
||||
About this Guide
|
||||
----------------
|
||||
|
||||
This guide will walk you through the installation and configuration of
|
||||
the native Microsoft Outlook compatibility layer SOGo offers.
|
||||
|
||||
Prior going over this guide, you should have a working SOGo
|
||||
installation. Please refer to the _SOGo Installation and Configuration
|
||||
Guide_ for more information on installing and configuring SOGo.
|
||||
|
||||
This guide also includes instructions for configuring Microsoft Outlook
|
||||
with SOGo.
|
||||
|
||||
The instructions are based on version {release_version} of SOGo.
|
||||
|
||||
The latest version of this guide is available
|
||||
at http://www.sogo.nu/downloads/documentation.html.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
SOGo is a free and modern scalable groupware server. It offers shared
|
||||
calendars, address books, and emails through your favourite Web browser
|
||||
and by using a native client such as Mozilla Thunderbird and Lightning.
|
||||
|
||||
SOGo is standard-compliant. It supports CalDAV, CardDAV, GroupDAV, iMIP
|
||||
and iTIP and reuses existing IMAP, SMTP and database servers — making
|
||||
the solution easy to deploy and interoperable with many applications.
|
||||
|
||||
SOGo features:
|
||||
|
||||
* Scalable architecture suitable for deployments from dozen to many
|
||||
thousand users
|
||||
* Rich Web-based interface that shares the look and feel, the features
|
||||
and the data of Mozilla Thunderbird and Lightning
|
||||
* Improved integration with Mozilla Thunderbird and Lightning by using
|
||||
the SOGo Connector and the SOGo Integrator
|
||||
* Native compatibility for Microsoft Outlook 2003, 2007, 2010, and 2013
|
||||
* Two-way synchronization support with any Microsoft ActiveSync-capable
|
||||
device, and Outlook 2013
|
||||
|
||||
SOGo is developed by a community of developers located mainly in North
|
||||
America and Europe. More information can be found
|
||||
on http://www.sogo.nu/.
|
||||
|
||||
Architecture
|
||||
------------
|
||||
|
||||
The following diagram demonstrates the architecture of the native
|
||||
Outlook compatibility layer of SOGo.
|
||||
|
||||
image::images/openchange.png[]
|
||||
|
||||
With Samba 4 and OpenChange, Microsoft Outlook clients can communicate
|
||||
natively with SOGo using the Microsoft Exchange protocol, without
|
||||
requiring costly and hard-to-maintain third-party MAPI connectors for
|
||||
Microsoft Outlook.
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Organizations generally have solutions to authenticate users such as
|
||||
LDAP servers or Microsoft Active Directory servers.
|
||||
|
||||
The solution being used will influence how users are provisioned in
|
||||
Samba 4, a key component for native Outlook compatibility in SOGo.
|
||||
|
||||
LDAP Server
|
||||
~~~~~~~~~~~
|
||||
|
||||
If your organization uses a LDAP server such OpenLDAP, Novell
|
||||
eDirectory, Apache Directory or any other solution, you must use
|
||||
Samba 4's internal directory server and synchronize the data between
|
||||
both.
|
||||
|
||||
Synchronization scripts are not provided and unless you have clear-text
|
||||
passwords of your existing users, they will have to be changed during
|
||||
your initial synchronization so that your LDAP's server passwords are
|
||||
identical to the ones from Samba 4.
|
||||
|
||||
Any modifications to your existing LDAP server (password change, user
|
||||
addition or deletion, etc.) will have to be replicated to Samba 4's
|
||||
internal directory server.
|
||||
|
||||
Note that if you install Samba 4 on a server that is already running a
|
||||
LDAP service, you will have to change to TCP port on which your LDAP
|
||||
server listens to. Samba 4 will use the TCP port 389 and it can't be
|
||||
changed.
|
||||
|
||||
For example, with OpenLDAP, you can use the `-h` parameter for `slapd`
|
||||
to make it listen on an other TCP port.
|
||||
|
||||
Microsoft Active Directory
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If your organization uses Microsoft Active Directory, Samba 4 will need
|
||||
to be joined to your Active Directory domain, as a DC.
|
||||
|
||||
Samba 4 will be able to reuse all the information contained in Microsoft
|
||||
Active Directory and no synchronization process needs to be put in place
|
||||
as information will get replicated to Samba 4 automatically.
|
||||
|
||||
For more information on joining Samba 4 to an existing Microsoft Active
|
||||
Directory domain, please refer to the Samba 4 documentation available at
|
||||
the following URL:
|
||||
|
||||
http://wiki.samba.org/index.php/Samba4
|
||||
|
||||
More specifically, have a look at the `samba-tool domain join` command.
|
||||
Note that joining Samba 4 to your Active Directory domain as a member
|
||||
will currently not work. An authentication bug is present in Samba 4
|
||||
which then prevents all Outlook users to successfully authenticate
|
||||
through Samba 4. This issue has been reported to the Samba team and is
|
||||
being worked on.
|
||||
|
||||
Other or No Solution
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If your organization neither uses a LDAP server or Microsoft Active
|
||||
Directory, you can start using Samba 4 as your directory server.
|
||||
|
||||
Samba 4's directory can be queried over LDAP just like Microsoft Active
|
||||
Directory and can also serve as a domain controller for Windows-based
|
||||
environments.
|
||||
|
||||
For example, SOGo can very well use Samba 4's built-in directory server
|
||||
to authenticate users. A SOGoUserSources entry to achieve this wold look
|
||||
like this:
|
||||
|
||||
----
|
||||
su – sogo
|
||||
defaults write sogod SOGoUserSources '(
|
||||
{
|
||||
CNFieldName = displayName;
|
||||
IDFieldName = cn;
|
||||
UIDFieldName = sAMAccountName;
|
||||
baseDN = "cn=Users,dc=example,dc=com";
|
||||
bindDN = "cn=Administrator,cn=Users,dc=example,dc=com";
|
||||
bindFields = (
|
||||
sAMAccountName
|
||||
);
|
||||
bindPassword = "%1OpenChange";
|
||||
canAuthenticate = YES;
|
||||
displayName = "Shared Addresses";
|
||||
hostname = "127.0.0.1";
|
||||
id = samba;
|
||||
isAddressBook = YES;
|
||||
port = 389;
|
||||
}
|
||||
)'
|
||||
----
|
||||
|
||||
Please refer to the _SOGo Installation and Configuration Guide_ for more
|
||||
information regarding `SOGoUserSources`.
|
||||
|
||||
IMAP Server and Trust
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
An IMAP server supporting the ACL, UIDPLUS and QRESYNC IMAP extensions
|
||||
is required, such as Cyrus IMAP version 2.4 or later, or Dovecot version
|
||||
2.1 or later. If your current IMAP server does not support these
|
||||
extensions, you can use Dovecot's proxying capabilities. The follow
|
||||
configuration example makes Dovecot proxy all IMAP request to an
|
||||
existing server:
|
||||
|
||||
----
|
||||
auth_mechanisms = plain login
|
||||
imapc_host = inverse.ca
|
||||
imapc_port = 993
|
||||
imapc_ssl = imaps
|
||||
imapc_ssl_verify = no
|
||||
mail_gid = imapproxy
|
||||
mail_home = /home/imapproxy/%u
|
||||
mail_location = imapc:~/imapc
|
||||
mail_uid = imapproxy
|
||||
passdb {
|
||||
args = host=inverse.ca ssl=imaps port=993 ssl_ca_dir=/etc/pki/tls/certs
|
||||
default_fields = userdb_imapc_user=%u userdb_imapc_password=%w
|
||||
driver = imap
|
||||
}
|
||||
protocols = imap
|
||||
ssl = no
|
||||
userdb {
|
||||
driver = prefetch
|
||||
}
|
||||
----
|
||||
|
||||
SOGo would then be configured to use Dovecot's proxy as the IMAP server.
|
||||
|
||||
Moreover, the authentication mode in use by Windows with Samba and
|
||||
Exchange servers prevent the backend from knowing the real password
|
||||
being used by the user. This implies that the IMAP server must accept
|
||||
any passwords from the host on which Samba is running.
|
||||
|
||||
To accomplish this with Cyrus IMAP Server, set `sasl_pwcheck_method`
|
||||
to `alwaystrue` in `/etc/imapd.conf`. You should restrain this to
|
||||
an `imapd` instance dedicated to SOGo.
|
||||
|
||||
For Dovecot, use an authentication source similar to:
|
||||
|
||||
----
|
||||
passdb {
|
||||
driver = static
|
||||
args = nopassword=y allow_nets=127.0.0.1/32
|
||||
}
|
||||
----
|
||||
|
||||
You should also make sure that you restrain this only to the SOGo
|
||||
processes.
|
||||
|
||||
For any other IMAP server, refer to the product's documentation. If such
|
||||
capability is not offered, you can alternatively define the cleartext
|
||||
password for each user. Please refer to the _Adding Users_ section from
|
||||
this document.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
This section will guide you through the installation of the native
|
||||
Microsoft Outlook compatibility layer SOGo offers.
|
||||
|
||||
Red Hat Enterprise Linux v6 x86_64
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you are using Red Hat Enterprise Linux version 6 x86_64, packages
|
||||
for Samba 4, OpenChange and SOGo and the SOGo OpenChange backend are
|
||||
available from SOGo's web site. Please follow the instructions from
|
||||
http://www.sogo.nu/english/downloads/backend.html.
|
||||
|
||||
In order to satisfy certain dependencies, you should also add the EPEL
|
||||
source corresponding to your distribution and architecture. More
|
||||
information on this is available here:
|
||||
http://fedoraproject.org/wiki/EPEL – or more specifically,
|
||||
http://fedoraproject.org/wiki/EPEL/FAQ#How_can_I_install_the_packages_from_the_EPEL_software_repository.3F.
|
||||
|
||||
Once ready, install the OpenChange packages on top of an existing SOGo
|
||||
installation:
|
||||
|
||||
----
|
||||
yum clean all && yum makecache
|
||||
yum install samba \
|
||||
openchange \
|
||||
sogo-openchange-backend \
|
||||
openchange-ocsmanager \
|
||||
openchange-rpcproxy \
|
||||
mysql-server \
|
||||
MySQL-python
|
||||
----
|
||||
|
||||
Once the packages are installed, refer to the _Configuration_ chapter
|
||||
from this guide.
|
||||
|
||||
[NOTE]
|
||||
Samba4/OpenChange are not available for now on CentOS 5 i386/x86_64,
|
||||
and CentOS 7. On Debian-based systems, packages are available only on
|
||||
the x86_64 platform.
|
||||
|
||||
Debian 7 (Wheezy) and Ubuntu 12.04 (Precise Pangolin)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
SOGo, OpenChange and the SOGo OpenChange backend are now
|
||||
available from SOGo's web site. Please follow the instructions from
|
||||
http://www.sogo.nu/english/downloads/backend.html to setup your
|
||||
apt sources.
|
||||
|
||||
On Debian7, for some Samba 4 dependencies, you need to use the
|
||||
_wheezy-backports_ repository. To do so, create
|
||||
`/etc/apt/sources.list.d/backports.list` with the following
|
||||
content:
|
||||
|
||||
deb http://http.debian.net/debian wheezy-backports main
|
||||
|
||||
Then install Samba 4 on top of an existing SOGo
|
||||
installation:
|
||||
|
||||
----
|
||||
apt-get update
|
||||
apt-get install samba samba-dev
|
||||
----
|
||||
|
||||
Once completed, install the packages related to OpenChange and the SOGo
|
||||
provider:
|
||||
|
||||
----
|
||||
apt-get install openchangeserver \
|
||||
sogo-openchange \
|
||||
openchangeproxy \
|
||||
python-ocsmanager \
|
||||
mysql-server \
|
||||
python-mysqldb \
|
||||
openchange-ocsmanager \
|
||||
openchange-rpcproxy \
|
||||
python-sievelib \
|
||||
python-spyne \
|
||||
python-rpclib
|
||||
----
|
||||
|
||||
Once the packages are installed, refer to the _Configuration_ chapter
|
||||
from this guide.
|
||||
|
||||
[NOTE]
|
||||
On Ubuntu 12.04, the Samba init scripts need to be modified to
|
||||
disable the upstart check. For more details, refer to:
|
||||
https://wiki.samba.org/index.php/Samba4/InitScript
|
||||
|
||||
|
||||
Debian 8 (Jessie) and Ubuntu 14.04 (Trusty Tahr)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Please follow the instructions from
|
||||
http://www.sogo.nu/english/downloads/backend.html to setup your
|
||||
apt sources.
|
||||
|
||||
Then install Samba 4 on top of an existing SOGo
|
||||
installation:
|
||||
|
||||
----
|
||||
apt-get update
|
||||
apt-get install samba samba-dev
|
||||
----
|
||||
|
||||
Once completed, install the packages related to OpenChange and the SOGo
|
||||
provider:
|
||||
|
||||
----
|
||||
apt-get install openchangeserver \
|
||||
sogo-openchange \
|
||||
openchangeproxy \
|
||||
python-ocsmanager \
|
||||
mysql-server \
|
||||
python-mysqldb \
|
||||
openchange-ocsmanager \
|
||||
openchange-rpcproxy \
|
||||
python-sievelib \
|
||||
python-spyne \
|
||||
python-rpclib
|
||||
----
|
||||
|
||||
Once the packages are installed, refer to the _Configuration_ chapter
|
||||
from this guide.
|
||||
|
||||
[NOTE]
|
||||
The `ocsmanager.conf` and `rpcproxy.conf` are currently located in
|
||||
`/etc/apache2/conf.d`. These should be moved to `/etc/apache2/conf-available`.
|
||||
This is a packaging error that will soon be fixed.
|
||||
|
||||
[NOTE]
|
||||
You might have to adjust the `rpcproxy.conf` configuration file to add the
|
||||
`Require all granted` permission if you get Apache errors such as
|
||||
`client denied by server configuration`.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
In this section, you'll learn how to configure the native Microsoft
|
||||
Outlook compatibility layer that SOGo offers.
|
||||
|
||||
SOGo Configuration
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
First thing to do is to configure SOGo to use your current services,
|
||||
which are your IMAP, SMTP and SQL database servers. The configuration
|
||||
instructions for this are available in the SOGo Installation and
|
||||
Configuration Guide available from http://www.sogo.nu/.
|
||||
|
||||
Please refer to that documentation before continuing with the
|
||||
instructions included in this guide.
|
||||
|
||||
Samba 4 Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Run the following commands as root:
|
||||
|
||||
----
|
||||
samba-tool domain provision --realm=example.com \
|
||||
--domain=OPENCHANGE \
|
||||
--adminpass='%1OpenChange' \
|
||||
--server-role='domain controller'
|
||||
|
||||
samba-tool user setexpiry administrator --noexpiry
|
||||
----
|
||||
|
||||
You might consider changing the realm and domain used, to suit your
|
||||
enviroment.
|
||||
|
||||
You might also have to
|
||||
remove `/etc/samba/smb.conf` prior running this command.
|
||||
|
||||
Add the following parameters to the `[global]` section of the
|
||||
`/etc/samba/smb.conf` configuration file:
|
||||
|
||||
----
|
||||
### Configuration required by OpenChange server ###
|
||||
dsdb:schema update allowed = true
|
||||
dcerpc endpoint servers = epmapper, mapiproxy, dnsserver
|
||||
dcerpc_mapiproxy:server = true
|
||||
dcerpc_mapiproxy:interfaces = exchange_emsmdb, exchange_nsp, exchange_ds_rfr
|
||||
### Configuration required by OpenChange server ###
|
||||
----
|
||||
|
||||
Your Samba 4 configuration file should look like this:
|
||||
|
||||
----
|
||||
# Global parameters
|
||||
[global]
|
||||
server role = active directory domain controller
|
||||
workgroup = EXAMPLE
|
||||
realm = example.com
|
||||
netbios name = sogo
|
||||
passdb backend = samba4
|
||||
### Configuration required by OpenChange server ###
|
||||
dsdb:schema update allowed = true
|
||||
dcerpc endpoint servers = +epmapper, +mapiproxy
|
||||
dcerpc_mapiproxy:server = true
|
||||
dcerpc_mapiproxy:interfaces = exchange_emsmdb, exchange_nsp, exchange_ds_rfr
|
||||
### Configuration required by OpenChange server ###
|
||||
|
||||
[netlogon]
|
||||
path = /var/lib/samba/sysvol/example.com/scripts
|
||||
read only = No
|
||||
|
||||
[sysvol]
|
||||
path = /var/lib/samba/sysvol
|
||||
read only = No
|
||||
----
|
||||
|
||||
OpenChange Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
OpenChange 2.2 stores its metadata in MySQL so you need to have it installed.
|
||||
|
||||
First, create the OpenChange MySQL user:
|
||||
|
||||
----
|
||||
$ mysql -u root -p
|
||||
mysql> CREATE USER 'openchange-user'@'localhost' IDENTIFIED BY 'openchange$123';
|
||||
mysql> GRANT ALL PRIVILEGES ON `openchange`.* TO 'openchange-user'@'localhost' WITH GRANT OPTION;
|
||||
mysql> FLUSH PRIVILEGES;
|
||||
----
|
||||
|
||||
The Samba AD schema needs to be filled with additional object
|
||||
definitions by running the following commands:
|
||||
|
||||
----
|
||||
openchange_provision --standalone
|
||||
|
||||
NOTE: This operation can take several minutes
|
||||
[+] Step 1: Register Exchange OIDs
|
||||
[+] Step 2: Add Exchange attributes to Samba schema
|
||||
[+] Step 3: Add Exchange auxiliary classes to Samba schema
|
||||
[+] Step 4: Add Exchange objectCategory to Samba schema
|
||||
[+] Step 5: Add Exchange containers to Samba schema
|
||||
[+] Step 6: Add Exchange *sub* containers to Samba schema
|
||||
[+] Step 7: Add Exchange CfgProtocol subcontainers to Samba schema
|
||||
[+] Step 8: Add Exchange mailGateway subcontainers to Samba schema
|
||||
[+] Step 9: Add Exchange classes to Samba schema
|
||||
[+] Step 10: Add possSuperior attributes to Exchange classes
|
||||
[+] Step 11: Extend existing Samba classes and attributes
|
||||
[+] Step 12: Generic Exchange configuration objects
|
||||
[+] Step 13: Finalize generic Exchange configuration objects
|
||||
[SUCCESS] Done!
|
||||
[+] Step 1: Exchange Samba registration
|
||||
[SUCCESS] Done!
|
||||
[+] Step 1: Register Exchange Samba as the main server
|
||||
[SUCCESS] Done!
|
||||
----
|
||||
|
||||
Create the OpenChange database:
|
||||
|
||||
----
|
||||
openchange_provision --openchangedb --openchangedb-uri 'mysql://openchange-user:openchange$123@localhost/openchange'
|
||||
|
||||
Setting up openchange db
|
||||
[+] Public Folders
|
||||
===================
|
||||
* Public Folder Root : 0x0100000000000001 (72057594037927937)
|
||||
* IPM_SUBTREE : 0x0200000000000001 (144115188075855873)
|
||||
* NON_IPM_SUBTREE : 0x0300000000000001 (216172782113783809)
|
||||
* EFORMS REGISTRY : 0x0400000000000001 (288230376151711745)
|
||||
* OFFLINE ADDRESS BOOK : 0x0500000000000001 (360287970189639681)
|
||||
* /o=First Organization/cn=addrlists/cn=oabs/cn=Default Offline Address Book: 0x0600000000000001 (432345564227567617)
|
||||
* SCHEDULE+ FREE BUSY : 0x0700000000000001 (504403158265495553)
|
||||
* EX:/o=first organization/ou=first administrative group: 0x0800000000000001 (576460752303423489)
|
||||
* Events Root : 0x0900000000000001 (648518346341351425)
|
||||
----
|
||||
|
||||
Finally, modify `/etc/samba/smb.conf` to specify OpenChange connection information
|
||||
for its indexing database. Add the following at the end of the `[global]` section:
|
||||
|
||||
----
|
||||
mapistore:namedproperties = mysql
|
||||
namedproperties:mysql_user = openchange-user
|
||||
namedproperties:mysql_pass = openchange$123
|
||||
namedproperties:mysql_host = localhost
|
||||
namedproperties:mysql_db = openchange
|
||||
|
||||
mapistore:indexing_backend = mysql://openchange-user:openchange$123@localhost/openchange
|
||||
mapiproxy:openchangedb = mysql://openchange-user:openchange$123@localhost/openchange
|
||||
----
|
||||
|
||||
On RHEL, make sure SELinux is disabled:
|
||||
|
||||
setenforce 0
|
||||
|
||||
Next, you can start Samba using the usual command:
|
||||
|
||||
/etc/init.d/samba start
|
||||
|
||||
On upstart-based distributions, use:
|
||||
|
||||
start samba-ad-dc
|
||||
|
||||
You can also launch the OpenChange web services:
|
||||
|
||||
/etc/init.d/openchange-ocsmanager start
|
||||
|
||||
Apache Configuration for Web Services
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The OpenChange web services consist of two components:
|
||||
|
||||
1. *OCS Manager* which is used for autodiscovery and freebusy lookups on
|
||||
Outlook 2007 and 2010. This service runs in its own application server
|
||||
which listens on `127.0.0.1:5000` by default. Apache needs to be
|
||||
configured to forward certain requests to it to make it accessible from
|
||||
the outside.
|
||||
Note that this service *MUST* be accessible over*HTTPS*, otherwise Outlook
|
||||
won't use it.
|
||||
2. *RPC Proxy* which is used for RPC over HTTP ("Outlook Anywhere").
|
||||
This service runs as a WSGI application under apache (mod_wsgi).
|
||||
While HTTPS is not required to access this service, it is strongly
|
||||
recommended.
|
||||
|
||||
On RHEL-based distributions, the apache configuration required by these
|
||||
services can be found in `/etc/httpd/conf.d/ocsmanager.conf` and
|
||||
`/etc/httpd/conf.d/rpcproxy.conf`.
|
||||
|
||||
For Debian-based distributions, these files can be found
|
||||
in `/etc/apache2/conf.d/` or `/etc/apache2/conf-available`.
|
||||
|
||||
The configuration requires three Apache modules: _mod_proxy_,
|
||||
_mod_proxy_http_ and _mod_wsgi_. These are usually already installed but
|
||||
might need to be activated on Debian-based installations:
|
||||
|
||||
a2enmod proxy proxy_http wsgi
|
||||
|
||||
The OCS Manager and RPC Proxy configuration module can be enabled using:
|
||||
|
||||
a2enconf ocsmanager
|
||||
a2enconf rpcproxy
|
||||
|
||||
On RHEL-based distributions, make sure the `LoadModule` directive is
|
||||
uncommented in `/etc/httpd/conf.d/wsgi.conf`.
|
||||
|
||||
The _reqtimeout_ apache module is known to cause problems when using the
|
||||
default configuration shipped with Debian-based systems. On such
|
||||
distributions, Apache will close (HTTP/1.1 500) any HTTP request for
|
||||
which the HTTP body hasn't arrived in 10 seconds.
|
||||
|
||||
While this is arguably good practice with regular HTTP, it will disrupt
|
||||
the RPC over HTTP protocol implemented by RPC Proxy: Outlook will
|
||||
continuously disconnect and reconnect leading to suboptimal performance.
|
||||
|
||||
To avoid this problem, use a much higher timeout or disable the module:
|
||||
|
||||
a2dismod reqtimeout
|
||||
|
||||
You should now restart the Apache service and make sure it will start on
|
||||
boot. On RHEL-based distributions, do:
|
||||
|
||||
chkconfig httpd on && /etc/init.d/httpd restart
|
||||
|
||||
On Debian-based distributions, do:
|
||||
|
||||
update-rc.d apache2 defaults && /etc/init.d/apache2 restart
|
||||
|
||||
Finally, you must adjust the OCS Manager configuration file, which is
|
||||
located in `/etc/ocsmanager/ocsmanager.ini`. You should enable LDAP-based
|
||||
authentication in the `main` section and configure it accordingly. You should
|
||||
also enable rpcproxy. You file should be similar to this one:
|
||||
|
||||
----
|
||||
[DEFAULT]
|
||||
debug = true
|
||||
email_to = you@yourdomain.com
|
||||
smtp_server = localhost
|
||||
error_email_from = paste@localhost
|
||||
|
||||
[main]
|
||||
auth = ldap
|
||||
mapistore_root = /var/lib/samba/private
|
||||
mapistore_data = /var/lib/samba/private/mapistore
|
||||
debug = yes
|
||||
|
||||
[auth:file]
|
||||
|
||||
[auth:ldap]
|
||||
host = ldap://127.0.0.1
|
||||
port = 389
|
||||
bind_dn = cn=administrator,cn=Users,dc=example,dc=com
|
||||
bind_pw = %1OpenChange
|
||||
basedn = cn=Users,dc=example,dc=com
|
||||
|
||||
[auth:single]
|
||||
username = openchange
|
||||
password = {SSHA}I6Hy5Wv0wuxyXvMBFWFQDVVN12_CLaX9
|
||||
|
||||
[server:main]
|
||||
use = egg:Paste#http
|
||||
host = 127.0.0.1
|
||||
port = 5000
|
||||
protocol_version = HTTP/1.1
|
||||
|
||||
[app:main]
|
||||
use = egg:ocsmanager
|
||||
full_stack = true
|
||||
static_files = true
|
||||
cache_dir = %(here)s/data
|
||||
beaker.session.key = ocsmanager
|
||||
beaker.session.secret = SDyKK3dKyDgW0mlpqttTMGU1f
|
||||
app_instance_uuid = {ee533ebc-f266-49d1-ae10-d017ee6aa98c}
|
||||
NTLMAUTHHANDLER_WORKDIR = /var/cache/ntlmauthhandler
|
||||
SAMBA_HOST = 127.0.0.1
|
||||
|
||||
[rpcproxy:ldap]
|
||||
host = localhost
|
||||
port = 389
|
||||
basedn = CN=Users,DC=example,DC=com
|
||||
set debug = true
|
||||
----
|
||||
|
||||
----
|
||||
[autodiscover]
|
||||
|
||||
[autodiscover:rpcproxy]
|
||||
enabled = true
|
||||
|
||||
[outofoffice]
|
||||
|
||||
[outofoffice:file]
|
||||
sieve_script_path = /var/vmail/$domain/$user/sieve-script
|
||||
sieve_script_path_mkdir = false
|
||||
|
||||
[outofoffice:managesieve]
|
||||
secret = secret
|
||||
|
||||
[loggers]
|
||||
keys = root
|
||||
|
||||
[handlers]
|
||||
keys = console
|
||||
|
||||
[formatters]
|
||||
keys = generic
|
||||
|
||||
[logger_root]
|
||||
level = INFO
|
||||
handlers = console
|
||||
|
||||
[handler_console]
|
||||
class = StreamHandler
|
||||
args = (sys.stderr,)
|
||||
level = NOTSET
|
||||
formatter = generic
|
||||
|
||||
[formatter_generic]
|
||||
format = %(asctime)s %(levelname)-5.5s [%(name)s] [%(threadName)s] %(message)s
|
||||
----
|
||||
|
||||
Once completed, start the OCS Manager service:
|
||||
|
||||
/etc/init.d/openchange-ocsmanager start
|
||||
|
||||
Name Service Configuration for Web Services
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The autodiscovery service must be made accessible in order to advertise
|
||||
the web services provided by OpenChange. This can be done in two ways.
|
||||
|
||||
1. The first is to associate the FQDN `autodiscover.example.com.` with
|
||||
the machine that hosts Samba 4 / OpenChange, by adding a `CNAME` entry
|
||||
in your DNS configuration. Note that, instead or changing your DNS
|
||||
server configuration, you can simply add a similar entry to the _hosts_
|
||||
file of the Windows machine from where you'll run Outlook, which is
|
||||
handy for testing purposes.
|
||||
2. The second option is to add a `SRV` entry to your DNS configuration
|
||||
where the `_service` value would be `Autodiscover` and the `_protocol`
|
||||
would be `_tcp`.
|
||||
|
||||
For example:
|
||||
|
||||
_autodiscover._tcp.example.com. IN SRV 0 0 443 sogo.example.com.
|
||||
|
||||
Again, the autodiscovery service must be accessible over HTTPS.
|
||||
|
||||
Adding Users
|
||||
------------
|
||||
|
||||
Users that wish to connect natively to SOGo must be provisioned in
|
||||
Samba 4 and in OpenChange – even if they already exist in your current
|
||||
LDAP or Microsoft Active Directory server.
|
||||
|
||||
To add a user, execute the following commands:
|
||||
|
||||
----
|
||||
# add user to samba
|
||||
samba-tool domain passwordsettings set --complexity=off
|
||||
samba-tool domain passwordsettings set --min-pwd-length=1
|
||||
samba-tool user add <username>
|
||||
samba-tool user setexpiry <username> --noexpiry
|
||||
# create user in openchange
|
||||
openchange_newuser --create <username>
|
||||
----
|
||||
|
||||
If you don't have a trust between your IMAP server and SOGo, you must at
|
||||
this point set the cleartext password of the newly created user in
|
||||
`/var/lib/samba/private/mapistore/<username/password`.
|
||||
|
||||
This per-user file contains the cleartext password of the user as a
|
||||
UTF-8 string, on a single line. This password will be used to
|
||||
authenticate SOGo/OpenChange storage provider to your IMAP server.
|
||||
|
||||
Microsoft Outlook Configuration
|
||||
-------------------------------
|
||||
|
||||
To connect Microsoft Outlook, you can either use the IP address of the
|
||||
server or its DNS name. If you prefer using the DNS name, add an entry
|
||||
like the following to the `c:\windows\system32\drivers\etc\hosts` file
|
||||
in order to associate the IP address with the right DNS names:
|
||||
|
||||
192.168.1.1 sogo.example.com autodiscover.example.com
|
||||
|
||||
Next, you must configure Microsoft Outlook.
|
||||
|
||||
* Open the Control Panel => Mail => Email Accounts.
|
||||
* Select _Add a new e-mail account_
|
||||
* Choose _Microsoft Exchange Server_
|
||||
* Fill the required information. Enter the DNS name or the IP address of
|
||||
your SOGo server in the _Microsoft Exchange Server_ field
|
||||
* Leave the _Use Cached Exchange Mode_ checkbox enabled
|
||||
* Enter your username in the _User Name_ field
|
||||
* Click on _More Settings_ and ignore the warning, if any, about
|
||||
Exchange being offline by clicking on Cancel
|
||||
* From the Security tab, enable Always prompt for user name and password
|
||||
* From the _Connection_ tab, enable _"Outlook Anywhere"_ if you plan to
|
||||
use Outlook outside of your LAN. Moreover, click on the _Exchange Proxy
|
||||
Settings..._ button to enable it for slow and fast networks. Specify
|
||||
also the host, which should be the same value you specified in the
|
||||
Microsoft Exchange Server field.
|
||||
* Finally, click on Check Name and confirm your username and password
|
||||
|
||||
Start Microsoft Outlook and enter your username and password. It will
|
||||
start to synchronize your mailbox. This could take a long time if you
|
||||
have many emails, events, tasks and contacts. Once this step is
|
||||
completed, check the autodiscovery service with Outlook 2007 or 2010 by
|
||||
simultaneously holding the CTRL key on your keyboard and right-clicking
|
||||
on the Outlook icon in the notification toolbar. A special entry named
|
||||
"Test E-mail AutoConfiguration..." will appear and will enable you to
|
||||
check the service.
|
||||
|
||||
Known Issues or Limitations
|
||||
---------------------------
|
||||
|
||||
* Make sure you periodically backup all your data regarding SOGo.
|
||||
* Make sure you have no firewalls activated between your Microsoft
|
||||
Outlook clients and the SOGo server with Native Outlook Compatibility
|
||||
module. If you do, use "Outlook Anywhere" to connect Outlook to
|
||||
SOGo/OpenChange.
|
||||
|
||||
Current Limitations
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The current version of the Native Microsoft Outlook compatibility layer
|
||||
has some limitations.
|
||||
|
||||
Those limitations will be overcome in the upcoming releases. If you are
|
||||
interested in having those limitations fixed more rapidly, please
|
||||
contact Inverse by sending an email to support@inverse.ca.
|
||||
|
||||
General
|
||||
^^^^^^^
|
||||
|
||||
* If you can't see any email's content with Microsoft Outlook 2007,
|
||||
install the latest Service Pack available from Microsoft's website for
|
||||
this specific version. Microsoft Outlook 2007 (12.0.6423.100) SP2 MSO
|
||||
(12.0.6425.1000) is known to work.
|
||||
* When you create a new Microsoft Outlook profile, not all folders might
|
||||
be synchronized during the first start. Simply select the appropriate
|
||||
folder and click "Send and Receive". Synchronizing a folder may take
|
||||
some time. For example, a folder with 1000 email messages might take
|
||||
around 5 minutes based on the underlying hardware.
|
||||
* Errors when synchronizing the "Offline Address Book" are normal and
|
||||
can be ignored for now. This feature is currently not supported.
|
||||
* If you face strange issues from Microsoft Outlook, you might want to
|
||||
remove any data associated with the user from the SOGo server and
|
||||
recreate a Microsoft Outlook profile.
|
||||
To remove any data associated to a user, use
|
||||
the `openchange_user_cleanup` script distributed with SOGo. The script
|
||||
can be found in `/usr/share/doc/sogo/` (`/usr/share/sogo-VERSION/` on
|
||||
RHEL).
|
||||
To reset a user, run the script as root:
|
||||
`python openchange_user_cleanup username`. See the usage output for additional options.
|
||||
* The "Out of Office Assistant" will not currently work. This feature
|
||||
has not been implemented.
|
||||
* Creating folders below INBOX (when not normally permitted by the IMAP
|
||||
server), below the Personal Calendar or Personal Address Book will work
|
||||
in Outlook cached mode but the server-side operation will fail and these
|
||||
folders will never be created. Potentially data loss can occur if the
|
||||
Outlook profile is destroyed. If you wan to create additional top-level
|
||||
mail folders, calendars or address books, open Outlook's folder list,
|
||||
select the top level node (usually, "email@example.com") and choose "New
|
||||
Folder..." from the contextual menu. Choose the relevant item types.
|
||||
|
||||
Mail
|
||||
^^^^
|
||||
|
||||
* Sharing mail folders is not supported.
|
||||
* To avoid possibly lossy conversion from RTF to HTML, Outlook should be
|
||||
configured to send all mails as HTML (or plaintext) instead of _Outlook
|
||||
Rich Text Format_.
|
||||
|
||||
Calendar
|
||||
^^^^^^^^
|
||||
|
||||
* Labels will not work.
|
||||
* It might be impossible to view event details from a shared calendar.
|
||||
This issue is being worked on.
|
||||
|
||||
Tasks
|
||||
^^^^^
|
||||
|
||||
* Tasks with start/due dates created from Outlook might not appear
|
||||
correctly in SOGo due to a timezone issue.
|
||||
* Reminders are not yet supported.
|
||||
* Assigning tasks will not work.
|
||||
|
||||
Contacts
|
||||
^^^^^^^^
|
||||
|
||||
* Categories will not work.
|
||||
* Distribution lists will not work.
|
||||
* Under Microsoft Outlook 2010, the special folder "Suggested Contacts"
|
||||
will not work.
|
||||
* The "Offline Address Book" will not work. This feature is not yet
|
||||
supported.
|
||||
|
||||
Notes
|
||||
^^^^^
|
||||
|
||||
* Notes are not synchronized in any ways with SOGo. The current version
|
||||
of SOGo lacks support for notes.
|
||||
|
||||
If you notice anything else, please send contact Inverse by sending an
|
||||
email to support@inverse.ca.
|
||||
|
||||
include::includes/additional-info.asciidoc[]
|
||||
|
||||
include::includes/commercial-support.asciidoc[]
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 433 KiB |
@@ -1,16 +0,0 @@
|
||||
#
|
||||
# fop fix to build our documentation on CentOS 6
|
||||
#
|
||||
# Inverse inc. <info@inverse.ca>
|
||||
#
|
||||
--- /usr/bin/fop.orig 2012-01-17 21:25:50.000000000 -0500
|
||||
+++ /usr/bin/fop 2012-01-17 21:26:04.000000000 -0500
|
||||
@@ -26,7 +26,7 @@
|
||||
# Set parameters
|
||||
set_jvm
|
||||
set_classpath commons-io batik-all avalon-framework xmlgraphics-commons \
|
||||
- commons-logging fop
|
||||
+ commons-logging fop xalan-j2
|
||||
set_flags $BASE_FLAGS
|
||||
set_options $BASE_OPTIONS
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#
|
||||
# xmlgraphics-fop fix to build our documentation on CentOS 5
|
||||
# taken from https://build.opensuse.org/request/show/68994
|
||||
#
|
||||
# Inverse inc. <info@inverse.ca>
|
||||
#
|
||||
--- /usr/bin/xmlgraphics-fop.orig 2012-01-17 18:42:08.000000000 -0500
|
||||
+++ /usr/bin/xmlgraphics-fop 2012-01-17 18:42:18.000000000 -0500
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
# Rest of the configuration
|
||||
MAIN_CLASS=org.apache.fop.cli.Main
|
||||
-BASE_JARS="xmlgraphics-fop xmlgraphics-batik/util xml-commons-jaxp-1.3-apis excalibur/avalon-framework-api xerces-j2 xalan-j2 xalan-j2-serializer"
|
||||
+BASE_JARS="xmlgraphics-fop batik-all xml-commons-jaxp-1.3-apis excalibur/avalon-framework-impl excalibur/avalon-framework-api xerces-j2 xalan-j2 xalan-j2-serializer"
|
||||
|
||||
# Set parameters
|
||||
set_jvm
|
||||
@@ -1,107 +0,0 @@
|
||||
<?xml version='1.0'?>
|
||||
<xsl:stylesheet
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
version="1.0">
|
||||
|
||||
<!-- ********************************************************************
|
||||
|
||||
Header / Footer customizations
|
||||
|
||||
This file is part of the SOGo project.
|
||||
Authors:
|
||||
- Inverse inc. <info@inverse.ca>
|
||||
|
||||
Copyright (C) 2011-2014 Inverse inc.
|
||||
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
|
||||
|
||||
******************************************************************** -->
|
||||
|
||||
<!--
|
||||
Here we are re-defining docbook-xsl/fo/pagesetup.xsl to fit our needs.
|
||||
- top: chapter number on the left
|
||||
- bottom: copyright, chapter name, page
|
||||
-->
|
||||
|
||||
<xsl:param name="header.rule" select="0"/>
|
||||
|
||||
<xsl:template name="header.content">
|
||||
<xsl:param name="pageclass" select="''"/>
|
||||
<xsl:param name="sequence" select="''"/>
|
||||
<xsl:param name="position" select="''"/>
|
||||
<xsl:param name="gentext-key" select="''"/>
|
||||
|
||||
<fo:block>
|
||||
<!-- sequence can be odd, even, first, blank -->
|
||||
<!-- position can be left, center, right -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="$sequence = 'blank'">
|
||||
<!-- nothing -->
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="($sequence='first' or $sequence='odd' or $sequence='even') and $position='left'">
|
||||
<xsl:if test="$pageclass != 'titlepage' and $pageclass != 'lot'">
|
||||
<xsl:call-template name="gentext">
|
||||
<xsl:with-param name="key" select="'chapter'"/>
|
||||
</xsl:call-template>
|
||||
<xsl:call-template name="gentext.space"/>
|
||||
<xsl:number count="chapter" from="book" level="any"/>
|
||||
</xsl:if>
|
||||
</xsl:when>
|
||||
|
||||
<!-- draft -->
|
||||
<xsl:when test="$position='right'">
|
||||
<xsl:call-template name="draft.text"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:otherwise>
|
||||
<!-- nop -->
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:param name="footer.rule" select="0"/>
|
||||
<xsl:template name="footer.content">
|
||||
<xsl:param name="pageclass" select="''"/>
|
||||
<xsl:param name="sequence" select="''"/>
|
||||
<xsl:param name="position" select="''"/>
|
||||
<xsl:param name="gentext-key" select="''"/>
|
||||
|
||||
<fo:block>
|
||||
<!-- pageclass can be front, body, back -->
|
||||
<!-- sequence can be odd, even, first, blank -->
|
||||
<!-- position can be left, center, right -->
|
||||
<xsl:choose>
|
||||
<xsl:when test="$pageclass = 'titlepage'">
|
||||
<!-- nop; no footer on title pages -->
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided = 0 and $position='left'">
|
||||
<xsl:apply-templates select="//copyright[1]" mode="titlepage.mode"/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="($sequence='first' or $sequence='odd' or $sequence='even') and $position='center'">
|
||||
<xsl:if test="$pageclass != 'titlepage' and $pageclass != 'lot'">
|
||||
<xsl:apply-templates select="." mode="titleabbrev.markup"/>
|
||||
</xsl:if>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$double.sided = 0 and $position='right'">
|
||||
<fo:page-number/>
|
||||
</xsl:when>
|
||||
|
||||
<xsl:when test="$sequence='blank'">
|
||||
<!-- nop -->
|
||||
</xsl:when>
|
||||
|
||||
<xsl:otherwise>
|
||||
<!-- nop -->
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
</xsl:stylesheet>
|
||||
<!-- vim: set shiftwidth=2 tabstop=2 expandtab: -->
|
||||
@@ -1,182 +0,0 @@
|
||||
<?xml version='1.0'?>
|
||||
<xsl:stylesheet
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
version="1.0">
|
||||
|
||||
<!-- ********************************************************************
|
||||
|
||||
SOGo Documentation Docbook FO Parameters
|
||||
|
||||
This file is part of the SOGo project.
|
||||
Authors:
|
||||
- Inverse inc. <info@inverse.ca>
|
||||
|
||||
Copyright (C) 2011-2014 Inverse inc.
|
||||
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
|
||||
|
||||
******************************************************************** -->
|
||||
|
||||
<!--
|
||||
Global Tasks
|
||||
|
||||
TODO prettier revhistory
|
||||
TODO prettier Table of Contents
|
||||
TODO generate PDF table of contents (like OSX's Preview shows on the right hand side)
|
||||
TODO title 2
|
||||
- align with text?
|
||||
- more above whitespace
|
||||
TODO change the bullet for a prettier one
|
||||
TODO title 3 and 4
|
||||
- align with text?
|
||||
- should be easier to differentiate (check network guide)
|
||||
TODO icon on line wrap in monospace boxes
|
||||
TODO caution, notes, warnings, etc.
|
||||
- box around it
|
||||
- sexy icon
|
||||
TODO -> is converted into an arrow but it's not pretty (is it font or docbook-thingy?)
|
||||
|
||||
-->
|
||||
|
||||
<!--
|
||||
Load default values
|
||||
|
||||
Real upstream schema is at:
|
||||
<xsl:import href="http://docbook.sourceforge.net/release/xsl/current/fo/docbook.xsl"/>
|
||||
|
||||
but we decided to load all sensible local xsd since it only produce a warning on missing imports.
|
||||
-->
|
||||
<!-- CentOS / RHEL -->
|
||||
<xsl:import href="/usr/share/sgml/docbook/xsl-stylesheets/fo/docbook.xsl"/>
|
||||
<!-- Debian / Ubuntu -->
|
||||
<xsl:import href="/usr/share/xml/docbook/stylesheet/docbook-xsl/fo/docbook.xsl"/>
|
||||
<!-- OSX through mac ports -->
|
||||
<xsl:import href="/opt/local/share/xsl/docbook-xsl/fo/docbook.xsl"/>
|
||||
|
||||
<!-- title page extra styling -->
|
||||
<xsl:import href="titlepage-fo.xsl"/>
|
||||
|
||||
<!-- header / footer extra styling -->
|
||||
<xsl:import href="headerfooter-fo.xsl"/>
|
||||
|
||||
<!-- attaching an image to the verso legalnotice component -->
|
||||
<xsl:template match="legalnotice" mode="book.titlepage.verso.mode">
|
||||
<xsl:apply-templates mode="titlepage.mode"/>
|
||||
<fo:block text-align="right">
|
||||
<fo:external-graphic src="url('images/inverse-logo.jpg')" width="3in" content-width="scale-to-fit"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<!-- stylesheet options -->
|
||||
<xsl:param name="title.font.family">Lato-Medium</xsl:param>
|
||||
<xsl:param name="chapter.autolabel" select="0"/>
|
||||
<xsl:attribute-set name="component.title.properties">
|
||||
<xsl:attribute name="padding-bottom">2.5em</xsl:attribute>
|
||||
<xsl:attribute name="border-bottom">solid 2px</xsl:attribute>
|
||||
<xsl:attribute name="margin-bottom">1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
<xsl:attribute-set name="section.title.level1.properties">
|
||||
<xsl:attribute name="border-bottom">solid 1px</xsl:attribute>
|
||||
<xsl:attribute name="margin-top">2em</xsl:attribute>
|
||||
<xsl:attribute name="margin-bottom">1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- titles spacing -->
|
||||
<xsl:attribute-set name="section.title.level2.properties">
|
||||
<xsl:attribute name="margin-top">1em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- default fonts -->
|
||||
<xsl:param name="body.font.family">Lato-Light</xsl:param>
|
||||
<xsl:param name="body.font.master">10</xsl:param>
|
||||
<xsl:param name="monospace.font.family">Incosolata</xsl:param>
|
||||
|
||||
<!-- revision table layout -->
|
||||
<xsl:attribute-set name="revhistory.title.properties">
|
||||
<xsl:attribute name="font-size">12pt</xsl:attribute>
|
||||
<xsl:attribute name="font-weight">bold</xsl:attribute>
|
||||
<xsl:attribute name="text-align">center</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
<xsl:attribute-set name="revhistory.table.properties">
|
||||
<xsl:attribute name="break-before">page</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
<xsl:attribute-set name="revhistory.table.cell.properties">
|
||||
<xsl:attribute name="border-bottom">1px solid</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- Table Of Contents (TOC) options -->
|
||||
<!-- We only want 2 level of ToC depth -->
|
||||
<xsl:param name="toc.section.depth" select="1"/>
|
||||
|
||||
<!-- titles left margin -->
|
||||
<xsl:attribute-set name="section.title.properties">
|
||||
<xsl:attribute name="start-indent"><xsl:value-of select="$body.start.indent"/></xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- lists type -->
|
||||
<xsl:template name="itemizedlist.label.markup">
|
||||
<xsl:param name="itemsymbol" select="'square'"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="$itemsymbol='square'"><fo:inline font-family="Lato-Light">▪</fo:inline></xsl:when>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
<xsl:template name="next.itemsymbol">
|
||||
<xsl:param name="itemsymbol" select="'default'"/>
|
||||
<xsl:choose>
|
||||
<xsl:otherwise>square</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
<!-- admonition -->
|
||||
<xsl:param name="admon.graphics" select="1"></xsl:param>
|
||||
<xsl:param name="admon.graphics.path">images/</xsl:param>
|
||||
<xsl:param name="admon.graphics.extension">.png</xsl:param>
|
||||
<xsl:attribute-set name="graphical.admonition.properties">
|
||||
<xsl:attribute name="border-top">1px solid</xsl:attribute>
|
||||
<xsl:attribute name="border-bottom">1px solid</xsl:attribute>
|
||||
<xsl:attribute name="padding-top">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="padding-bottom">0.5em</xsl:attribute>
|
||||
<xsl:attribute name="margin-left">2em</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
|
||||
<!-- grey boxes around code (screen, programlisting) -->
|
||||
<xsl:param name="shade.verbatim" select="1"/>
|
||||
<xsl:attribute-set name="shade.verbatim.style">
|
||||
<xsl:attribute name="background-color">#E0E0E0</xsl:attribute>
|
||||
<xsl:attribute name="border">thin #9F9F9F solid</xsl:attribute>
|
||||
<xsl:attribute name="margin">0pt</xsl:attribute>
|
||||
<xsl:attribute name="padding">0.5em</xsl:attribute>
|
||||
<!-- prevent page breaks in screen and programlisting tags -->
|
||||
<xsl:attribute name="keep-together.within-column">always</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- breaking long lines in code (screen, programlisting) -->
|
||||
<xsl:attribute-set name="monospace.verbatim.properties">
|
||||
<xsl:attribute name="wrap-option">wrap</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- don't show raw links in [ .. ] after a link -->
|
||||
<xsl:param name="ulink.show" select="0"/>
|
||||
|
||||
<!-- blue underlined hyperlink -->
|
||||
<xsl:attribute-set name="xref.properties">
|
||||
<xsl:attribute name="color">blue</xsl:attribute>
|
||||
<xsl:attribute name="text-decoration">underline</xsl:attribute>
|
||||
</xsl:attribute-set>
|
||||
|
||||
<!-- strong emphasis in bold -->
|
||||
<xsl:template match="emphasis[@role='strong']">
|
||||
<fo:inline font-family="Lato" font-weight="normal">
|
||||
<xsl:apply-templates/>
|
||||
</fo:inline>
|
||||
</xsl:template>
|
||||
|
||||
<!-- copyright in range instead of seperated years -->
|
||||
<xsl:param name="make.year.ranges" select="1" />
|
||||
|
||||
<!-- variablelist behavior (asciidoc's term:: lists) -->
|
||||
<!-- <xsl:param name="variablelist.term.break.after" select="1" /> -->
|
||||
|
||||
</xsl:stylesheet>
|
||||
<!-- vim: set shiftwidth=2 tabstop=2 expandtab: -->
|
||||
@@ -1,96 +0,0 @@
|
||||
<!DOCTYPE t:templates [
|
||||
<!ENTITY hsize0 "10pt">
|
||||
<!ENTITY hsize1 "12pt">
|
||||
<!ENTITY hsize2 "14.4pt">
|
||||
<!ENTITY hsize3 "17.28pt">
|
||||
<!ENTITY hsize4 "20.736pt">
|
||||
<!ENTITY hsize5 "24.8832pt">
|
||||
<!ENTITY hsize0space "7.5pt"> <!-- 0.75 * hsize0 -->
|
||||
<!ENTITY hsize1space "9pt"> <!-- 0.75 * hsize1 -->
|
||||
<!ENTITY hsize2space "10.8pt"> <!-- 0.75 * hsize2 -->
|
||||
<!ENTITY hsize3space "12.96pt"> <!-- 0.75 * hsize3 -->
|
||||
<!ENTITY hsize4space "15.552pt"> <!-- 0.75 * hsize4 -->
|
||||
<!ENTITY hsize5space "18.6624pt"> <!-- 0.75 * hsize5 -->
|
||||
]>
|
||||
<t:templates xmlns:t="http://nwalsh.com/docbook/xsl/template/1.0"
|
||||
xmlns:param="http://nwalsh.com/docbook/xsl/template/1.0/param"
|
||||
xmlns:fo="http://www.w3.org/1999/XSL/Format"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||
|
||||
<!-- ********************************************************************
|
||||
|
||||
SOGo title page
|
||||
|
||||
This file is part of the SOGo project.
|
||||
Authors:
|
||||
- Inverse inc. <info@inverse.ca>
|
||||
|
||||
Copyright (C) 2011-2014 Inverse inc.
|
||||
License: GFDL 1.2 or later. http://www.gnu.org/licenses/fdl.html
|
||||
|
||||
******************************************************************** -->
|
||||
|
||||
<!--
|
||||
If you make changes you need to rebuild XSL:
|
||||
|
||||
xsltproc -o docs/docbook/xsl/titlepage-fo.xsl \
|
||||
/usr/share/xml/docbook/stylesheet/docbook-xsl/template/titlepage.xsl \
|
||||
docs/docbook/xsl/titlepage-fo.xml
|
||||
|
||||
On some platforms the titlepage.xsl is located elsewhere:
|
||||
* OSX: /opt/local/share/xsl/docbook-xsl/template/titlepage.xsl
|
||||
|
||||
This is a customized version of docbook-xsl/fo/titlepage.templates.xml.
|
||||
I removed every section except the book one. Feel free to add more if more
|
||||
customization are required.
|
||||
-->
|
||||
|
||||
<t:titlepage t:element="book" t:wrapper="fo:block">
|
||||
<t:titlepage-content t:side="recto">
|
||||
<mediaobject/>
|
||||
<title
|
||||
t:named-template="division.title"
|
||||
param:node="ancestor-or-self::book[1]"
|
||||
text-align="right"
|
||||
font-size="&hsize5;"
|
||||
space-before="&hsize5space;"
|
||||
font-weight="bold"
|
||||
font-family="{$title.fontset}"
|
||||
margin-top="8em"/>
|
||||
<subtitle
|
||||
text-align="right"
|
||||
font-size="&hsize4;"
|
||||
space-before="&hsize4space;"
|
||||
font-family="{$title.fontset}"
|
||||
border-bottom="solid"/>
|
||||
</t:titlepage-content>
|
||||
|
||||
<t:titlepage-content t:side="verso">
|
||||
<title
|
||||
font-size="&hsize2;"
|
||||
font-weight="bold"
|
||||
font-family="{$title.fontset}"/>
|
||||
<corpauthor/>
|
||||
<authorgroup t:named-template="verso.authorgroup"/>
|
||||
<author/>
|
||||
<othercredit/>
|
||||
<releaseinfo space-before="0.5em"/>
|
||||
<pubdate space-before="1em"/>
|
||||
<copyright/>
|
||||
<abstract/>
|
||||
<legalnotice font-size="8pt"/>
|
||||
</t:titlepage-content>
|
||||
|
||||
<t:titlepage-separator>
|
||||
<fo:block break-after="page"/>
|
||||
</t:titlepage-separator>
|
||||
|
||||
<t:titlepage-before t:side="recto">
|
||||
</t:titlepage-before>
|
||||
|
||||
<t:titlepage-before t:side="verso">
|
||||
<fo:block break-after="page"/>
|
||||
</t:titlepage-before>
|
||||
</t:titlepage>
|
||||
|
||||
</t:templates>
|
||||
@@ -1,208 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" version="1.0" exclude-result-prefixes="exsl">
|
||||
|
||||
<!-- This stylesheet was created by template/titlepage.xsl-->
|
||||
|
||||
<xsl:template name="book.titlepage.recto">
|
||||
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="bookinfo/mediaobject"/>
|
||||
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="info/mediaobject"/>
|
||||
<xsl:choose>
|
||||
<xsl:when test="bookinfo/title">
|
||||
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="bookinfo/title"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="info/title">
|
||||
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="info/title"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="title">
|
||||
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="title"/>
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
|
||||
<xsl:choose>
|
||||
<xsl:when test="bookinfo/subtitle">
|
||||
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="bookinfo/subtitle"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="info/subtitle">
|
||||
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="info/subtitle"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="subtitle">
|
||||
<xsl:apply-templates mode="book.titlepage.recto.auto.mode" select="subtitle"/>
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="book.titlepage.verso">
|
||||
<xsl:choose>
|
||||
<xsl:when test="bookinfo/title">
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/title"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="info/title">
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/title"/>
|
||||
</xsl:when>
|
||||
<xsl:when test="title">
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="title"/>
|
||||
</xsl:when>
|
||||
</xsl:choose>
|
||||
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/corpauthor"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/corpauthor"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/authorgroup"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/authorgroup"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/author"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/author"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/othercredit"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/othercredit"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/releaseinfo"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/releaseinfo"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/pubdate"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/pubdate"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/copyright"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/copyright"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/abstract"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/abstract"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="bookinfo/legalnotice"/>
|
||||
<xsl:apply-templates mode="book.titlepage.verso.auto.mode" select="info/legalnotice"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="book.titlepage.separator"><fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" break-after="page"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="book.titlepage.before.recto">
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="book.titlepage.before.verso"><fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" break-after="page"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template name="book.titlepage">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format">
|
||||
<xsl:variable name="recto.content">
|
||||
<xsl:call-template name="book.titlepage.before.recto"/>
|
||||
<xsl:call-template name="book.titlepage.recto"/>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="recto.elements.count">
|
||||
<xsl:choose>
|
||||
<xsl:when test="function-available('exsl:node-set')"><xsl:value-of select="count(exsl:node-set($recto.content)/*)"/></xsl:when>
|
||||
<xsl:when test="contains(system-property('xsl:vendor'), 'Apache Software Foundation')">
|
||||
<!--Xalan quirk--><xsl:value-of select="count(exsl:node-set($recto.content)/*)"/></xsl:when>
|
||||
<xsl:otherwise>1</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:if test="(normalize-space($recto.content) != '') or ($recto.elements.count > 0)">
|
||||
<fo:block><xsl:copy-of select="$recto.content"/></fo:block>
|
||||
</xsl:if>
|
||||
<xsl:variable name="verso.content">
|
||||
<xsl:call-template name="book.titlepage.before.verso"/>
|
||||
<xsl:call-template name="book.titlepage.verso"/>
|
||||
</xsl:variable>
|
||||
<xsl:variable name="verso.elements.count">
|
||||
<xsl:choose>
|
||||
<xsl:when test="function-available('exsl:node-set')"><xsl:value-of select="count(exsl:node-set($verso.content)/*)"/></xsl:when>
|
||||
<xsl:when test="contains(system-property('xsl:vendor'), 'Apache Software Foundation')">
|
||||
<!--Xalan quirk--><xsl:value-of select="count(exsl:node-set($verso.content)/*)"/></xsl:when>
|
||||
<xsl:otherwise>1</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:variable>
|
||||
<xsl:if test="(normalize-space($verso.content) != '') or ($verso.elements.count > 0)">
|
||||
<fo:block><xsl:copy-of select="$verso.content"/></fo:block>
|
||||
</xsl:if>
|
||||
<xsl:call-template name="book.titlepage.separator"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="*" mode="book.titlepage.recto.mode">
|
||||
<!-- if an element isn't found in this mode, -->
|
||||
<!-- try the generic titlepage.mode -->
|
||||
<xsl:apply-templates select="." mode="titlepage.mode"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="*" mode="book.titlepage.verso.mode">
|
||||
<!-- if an element isn't found in this mode, -->
|
||||
<!-- try the generic titlepage.mode -->
|
||||
<xsl:apply-templates select="." mode="titlepage.mode"/>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="mediaobject" mode="book.titlepage.recto.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.recto.style">
|
||||
<xsl:apply-templates select="." mode="book.titlepage.recto.mode"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="title" mode="book.titlepage.recto.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.recto.style" text-align="right" font-size="24.8832pt" space-before="18.6624pt" font-weight="bold" font-family="{$title.fontset}" margin-top="8em">
|
||||
<xsl:call-template name="division.title">
|
||||
<xsl:with-param name="node" select="ancestor-or-self::book[1]"/>
|
||||
</xsl:call-template>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="subtitle" mode="book.titlepage.recto.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.recto.style" text-align="right" font-size="20.736pt" space-before="15.552pt" font-family="{$title.fontset}" border-bottom="solid">
|
||||
<xsl:apply-templates select="." mode="book.titlepage.recto.mode"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="title" mode="book.titlepage.verso.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style" font-size="14.4pt" font-weight="bold" font-family="{$title.fontset}">
|
||||
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="corpauthor" mode="book.titlepage.verso.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style">
|
||||
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="authorgroup" mode="book.titlepage.verso.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style">
|
||||
<xsl:call-template name="verso.authorgroup">
|
||||
</xsl:call-template>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="author" mode="book.titlepage.verso.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style">
|
||||
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="othercredit" mode="book.titlepage.verso.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style">
|
||||
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="releaseinfo" mode="book.titlepage.verso.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style" space-before="0.5em">
|
||||
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="pubdate" mode="book.titlepage.verso.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style" space-before="1em">
|
||||
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="copyright" mode="book.titlepage.verso.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style">
|
||||
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="abstract" mode="book.titlepage.verso.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style">
|
||||
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="legalnotice" mode="book.titlepage.verso.auto.mode">
|
||||
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" xsl:use-attribute-sets="book.titlepage.verso.style" font-size="8pt">
|
||||
<xsl:apply-templates select="." mode="book.titlepage.verso.mode"/>
|
||||
</fo:block>
|
||||
</xsl:template>
|
||||
|
||||
</xsl:stylesheet>
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<!-- TODO have the build system take care of this -->
|
||||
<releaseinfo>Version 2.3.1 - July 2015</releaseinfo>
|
||||
<subtitle>for version 2.3.1</subtitle>
|
||||
<date>2015-07-23</date>
|
||||
|
||||
<legalnotice>
|
||||
<para>Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".</para>
|
||||
|
||||
<!-- font licenses -->
|
||||
<para>The fonts used in this guide are licensed under the SIL Open Font License, Version 1.1. This license is available with a FAQ at: <ulink url="http://scripts.sil.org/OFL">http://scripts.sil.org/OFL</ulink></para>
|
||||
<para>Copyright © Łukasz Dziedzic, <ulink url="http://www.latofonts.com/">http://www.latofonts.com</ulink>, with Reserved Font Name: "Lato".</para>
|
||||
<para>Copyright © Raph Levien, <ulink url="http://levien.com/">http://levien.com/</ulink>, with Reserved Font Name: "Inconsolata".</para>
|
||||
</legalnotice>
|
||||
<mediaobject>
|
||||
<objectinfo>
|
||||
<corpname>Inverse inc.</corpname>
|
||||
</objectinfo>
|
||||
<textobject>
|
||||
<phrase>SOGo logo</phrase>
|
||||
</textobject>
|
||||
<imageobject>
|
||||
<imagedata align="left" width="4in" format="PNG" fileref="images/sogo-logo.png" />
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
@@ -1,32 +0,0 @@
|
||||
<fop version="1.0">
|
||||
<renderers>
|
||||
<renderer mime="application/pdf">
|
||||
<fonts>
|
||||
<font metrics-url="fonts/inconsolata.xml" kerning="yes" embed-url="fonts/inconsolata.ttf">
|
||||
<font-triplet name="Incosolata" style="normal" weight="normal"/>
|
||||
</font>
|
||||
<font metrics-url="fonts/lato/Lato-Regular.xml" kerning="yes" embed-url="fonts/lato/Lato-Regular.ttf">
|
||||
<font-triplet name="Lato" style="normal" weight="normal"/>
|
||||
</font>
|
||||
<font metrics-url="fonts/lato/Lato-Italic.xml" kerning="yes" embed-url="fonts/lato/Lato-Italic.ttf">
|
||||
<font-triplet name="Lato" style="italic" weight="normal"/>
|
||||
</font>
|
||||
<font metrics-url="fonts/lato/Lato-Light.xml" kerning="yes" embed-url="fonts/lato/Lato-Light.ttf">
|
||||
<font-triplet name="Lato-Light" style="normal" weight="normal"/>
|
||||
</font>
|
||||
<font metrics-url="fonts/lato/Lato-LightItalic.xml" kerning="yes" embed-url="fonts/lato/Lato-LightItalic.ttf">
|
||||
<font-triplet name="Lato-Light" style="italic" weight="normal"/>
|
||||
</font>
|
||||
<font metrics-url="fonts/lato/Lato-Medium.xml" kerning="yes" embed-url="fonts/lato/Lato-Medium.ttf">
|
||||
<font-triplet name="Lato-Medium" style="normal" weight="normal"/>
|
||||
</font>
|
||||
<font metrics-url="fonts/lato/Lato-MediumItalic.xml" kerning="yes" embed-url="fonts/lato/Lato-MediumItalic.ttf">
|
||||
<font-triplet name="Lato-Medium" style="italic" weight="normal"/>
|
||||
</font>
|
||||
<font metrics-url="fonts/lato/Lato-Semibold.xml" kerning="yes" embed-url="fonts/lato/Lato-Semibold.ttf">
|
||||
<font-triplet name="Lato-Semibold" style="normal" weight="normal"/>
|
||||
</font>
|
||||
</fonts>
|
||||
</renderer>
|
||||
</renderers>
|
||||
</fop>
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Inconsolata</font-name><full-name>Inconsolata</full-name><family-name>Inconsolata</family-name><embed/><cap-height>624</cap-height><x-height>458</x-height><ascender>820</ascender><descender>-180</descender><bbox><left>-1</left><bottom>-177</bottom><right>510</right><top>835</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="3" ue="126" us="32"/><bf gi="98" ue="255" us="160"/><bf gi="194" ue="263" us="258"/><bf gi="200" ue="273" us="268"/><bf gi="206" ue="283" us="280"/><bf gi="210" ue="287" us="286"/><bf gi="212" ue="305" us="304"/><bf gi="214" ue="314" us="312"/><bf gi="217" ue="318" us="317"/><bf gi="219" ue="324" us="321"/><bf gi="223" ue="328" us="327"/><bf gi="225" ue="331" us="330"/><bf gi="227" ue="333" us="333"/><bf gi="228" ue="341" us="336"/><bf gi="234" ue="347" us="344"/><bf gi="238" ue="357" us="350"/><bf gi="246" ue="369" us="366"/><bf gi="250" ue="382" us="376"/><bf gi="257" ue="402" us="402"/><bf gi="258" ue="567" us="567"/><bf gi="259" ue="711" us="710"/><bf gi="261" ue="713" us="713"/><bf gi="262" ue="715" us="715"/><bf gi="263" ue="733" us="728"/><bf gi="269" ue="8218" us="8216"/><bf gi="272" ue="8222" us="8220"/><bf gi="275" ue="8226" us="8224"/><bf gi="278" ue="8230" us="8230"/><bf gi="279" ue="8250" us="8249"/><bf gi="281" ue="8260" us="8260"/><bf gi="282" ue="8308" us="8308"/><bf gi="283" ue="8364" us="8364"/><bf gi="284" ue="8482" us="8482"/><bf gi="285" ue="8593" us="8593"/><bf gi="286" ue="8595" us="8595"/><bf gi="287" ue="8722" us="8722"/><bf gi="288" ue="9251" us="9251"/><bf gi="0" ue="65535" us="65535"/></bfranges><cid-widths start-index="0"><wx w="500"/><wx w="0"/><wx w="333"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wx w="500"/><wLine truncated
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Lato-Black</font-name><full-name>Lato Black</full-name><family-name>Lato</family-name><embed/><cap-height>728</cap-height><x-height>518</x-height><ascender>805</ascender><descender>-195</descender><bbox><left>-654</left><bottom>-299</bottom><right>1356</right><top>1116</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="1" ue="0" us="0"/><bf gi="171" ue="13" us="13"/><bf gi="2" ue="32" us="32"/><bf gi="82" ue="33" us="33"/><bf gi="122" ue="34" us="34"/><bf gi="134" ue="35" us="35"/><bf gi="130" ue="36" us="36"/><bf gi="166" ue="37" us="37"/><bf gi="123" ue="38" us="38"/><bf gi="121" ue="39" us="39"/><bf gi="108" ue="41" us="40"/><bf gi="114" ue="42" us="42"/><bf gi="144" ue="43" us="43"/><bf gi="84" ue="44" us="44"/><bf gi="102" ue="45" us="45"/><bf gi="87" ue="46" us="46"/><bf gi="99" ue="47" us="47"/><bf gi="135" ue="53" us="48"/><bf gi="164" ue="54" us="54"/><bf gi="141" ue="55" us="55"/><bf gi="165" ue="56" us="56"/><bf gi="142" ue="57" us="57"/><bf gi="86" ue="58" us="58"/><bf gi="85" ue="59" us="59"/><bf gi="149" ue="60" us="60"/><bf gi="146" ue="61" us="61"/><bf gi="150" ue="62" us="62"/><bf gi="83" ue="63" us="63"/><bf gi="124" ue="64" us="64"/><bf gi="3" ue="65" us="65"/><bf gi="5" ue="67" us="66"/><bf gi="8" ue="79" us="68"/><bf gi="22" ue="90" us="80"/><bf gi="110" ue="91" us="91"/><bf gi="101" ue="92" us="92"/><bf gi="111" ue="93" us="93"/><bf gi="119" ue="94" us="94"/><bf gi="105" ue="95" us="95"/><bf gi="68" ue="96" us="96"/><bf gi="33" ue="97" us="97"/><bf gi="35" ue="99" us="98"/><bf gi="38" ue="102" us="100"/><bf gi="43" ue="105" us="103"/><bf gi="47" ue="107" us="106"/><bf gi="163" ue="108" us="108"/><bf gi="49" ue="111" us="109"/><bf gi="54" ue="115" us="112"/><bf gi="59" ue="122" us="116"/><bf gi="112" ue="123" us="123"/><bf gi="100" ue="124" us="124"/><bf gi="113" ue="125" us="125"/><bf gi="120" ue="126" us="126"/><bf gi="2" ue="160" us="160"/><bf gi="167" ue="161" us="161"/><bf gi="131" ue="163" us="162"/><bf gi="455" ue="164" us="164"/><bf gi="133" ue="165" us="165"/><bf gi="452" ue="166" us="166"/><bf gi="117" ue="167" us="167"/><bf gi="73" ue="168" us="168"/><bf gi="125" ue="169" us="169"/><bf gi="66" ue="170" us="170"/><bf gi="97" ue="171" us="171"/><bf gi="154" ue="172" us="172"/><bf gi="102" ue="173" us="173"/><bf gi="126" ue="174" us="174"/><bf gi="74" ue="175" us="175"/><bf gi="128" ue="176" us="176"/><bf gi="151" ue="177" us="177"/><bf gi="1202" ue="179" us="178"/><bf gi="69" ue="180" us="180"/><bf gi="224" ue="181" us="181"/><bf gi="118" ue="182" us="182"/><bf gi="107" ue="183" us="183"/><bf gi="79" ue="184" us="184"/><bf gi="1204" ue="185" us="185"/><bf gi="67" ue="186" us="186"/><bf gi="98" ue="187" us="187"/><bf gi="1205" ue="190" us="188"/><bf gi="168" ue="191" us="191"/><bf gi="172" ue="197" us="192"/><bf gi="4" ue="198" us="198"/><bf gi="7" ue="199" us="199"/><bf gi="178" ue="207" us="200"/><bf gi="226" ue="208" us="208"/><bf gi="186" ue="214" us="209"/><bf gi="517" ue="215" us="215"/><bf gi="20" ue="216" us="216"/><bf gi="192" ue="220" us="217"/><bf gi="2203" ue="221" us="221"/><bf gi="233" ue="222" us="222"/><bf gi="58" ue="223" us="223"/><bf gi="197" ue="229" us="224"/><bf gi="34" ue="230" us="230"/><bf gi="37" ue="231" us="231"/><bf gi="203" ue="239" us="232"/><bf gi="244" ue="240" us="240"/><bf gi="211" ue="246" us="241"/><bf gi="145" ue="247" us="247"/><bf gi="52" ue="248" us="248"/><bf gi="217" ue="252" us="249"/><bf gi="2538" ue="253" us="253"/><bf gi="285" ue="254" us="254"/><bf gi="221" ue="255" us="255"/><bf gi="1889" ue="256" us="256"/><bf gi="2229" ue="257" us="257"/><bf gi="1890" ue="258" us="258"/><bf gi="2230" ue="259" us="259"/><bf gi="225" ue="260" us="260"/><bf gi="237" ue="261" us="261"/><bf gi="1947" ue="262" us="262"/><bf gi="2263" ue="263" us="263"/><bf gi="1948" ue="264" us="264"/><bf gi="2264" ue="265" us="265"/><bf gi="1950" ue="266" us="266"/><bf gi="2266" ue="267" us="267"/><bf gi="1949" ue="268" us="268"/><bf gi="2265" ue="269" us="269"/><bf gi="1955" ue="270" us="270"/><bf gi="242" ue="271" us="271"/><bf gi="1962" ue="272" us="272"/><bf gi="243" ue="273" us="273"/><bf gi="1965" ue="274" us="274"/><bf gi="2279" ue="275" us="275"/><bf gi="1966" ue="276" us="276"/><bf gi="2280" ue="277" us="277"/><bf gi="1967" ue="278" us="278"/><bf gi="2281" ue="279" us="279"/><bf gi="227" ue="280" us="280"/><bf gi="245" ue="281" us="281"/><bf gi="1964" ue="282" us="282"/><bf gi="2278" ue="283" us="283"/><bf gi="2000" ue="284" us="284"/><bf gi="2322" ue="285" us="285"/><bf gi="2001" ue="286" us="286"/><bf gi="2323" ue="287" us="287"/><bf gi="2002" ue="288" us="288"/><bf gi="2324" ue="289" us="289"/><bf gi="2003" ue="290" us="290"/><bf gi="2325" ue="291" us="291"/><bf gi="2007" ue="292" us="292"/><bf gi="276" ue="293" us=Line truncated
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Lato-BlackItalic</font-name><full-name>Lato Black Italic</full-name><family-name>Lato</family-name><embed/><cap-height>728</cap-height><x-height>518</x-height><ascender>805</ascender><descender>-195</descender><bbox><left>-537</left><bottom>-297</bottom><right>1295</right><top>1114</top></bbox><flags>97</flags><stemv>0</stemv><italicangle>-7</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="1" ue="0" us="0"/><bf gi="169" ue="13" us="13"/><bf gi="2" ue="32" us="32"/><bf gi="81" ue="33" us="33"/><bf gi="120" ue="34" us="34"/><bf gi="132" ue="35" us="35"/><bf gi="128" ue="36" us="36"/><bf gi="164" ue="37" us="37"/><bf gi="121" ue="38" us="38"/><bf gi="119" ue="39" us="39"/><bf gi="106" ue="41" us="40"/><bf gi="112" ue="42" us="42"/><bf gi="142" ue="43" us="43"/><bf gi="83" ue="44" us="44"/><bf gi="100" ue="45" us="45"/><bf gi="85" ue="46" us="46"/><bf gi="97" ue="47" us="47"/><bf gi="133" ue="53" us="48"/><bf gi="162" ue="54" us="54"/><bf gi="139" ue="55" us="55"/><bf gi="163" ue="56" us="56"/><bf gi="140" ue="57" us="57"/><bf gi="170" ue="58" us="58"/><bf gi="84" ue="59" us="59"/><bf gi="147" ue="60" us="60"/><bf gi="144" ue="61" us="61"/><bf gi="148" ue="62" us="62"/><bf gi="82" ue="63" us="63"/><bf gi="122" ue="64" us="64"/><bf gi="3" ue="65" us="65"/><bf gi="5" ue="67" us="66"/><bf gi="8" ue="79" us="68"/><bf gi="22" ue="90" us="80"/><bf gi="108" ue="91" us="91"/><bf gi="99" ue="92" us="92"/><bf gi="109" ue="93" us="93"/><bf gi="117" ue="94" us="94"/><bf gi="103" ue="95" us="95"/><bf gi="68" ue="96" us="96"/><bf gi="33" ue="97" us="97"/><bf gi="35" ue="99" us="98"/><bf gi="38" ue="102" us="100"/><bf gi="43" ue="105" us="103"/><bf gi="47" ue="107" us="106"/><bf gi="161" ue="108" us="108"/><bf gi="49" ue="111" us="109"/><bf gi="54" ue="115" us="112"/><bf gi="59" ue="122" us="116"/><bf gi="110" ue="123" us="123"/><bf gi="98" ue="124" us="124"/><bf gi="111" ue="125" us="125"/><bf gi="118" ue="126" us="126"/><bf gi="2" ue="160" us="160"/><bf gi="165" ue="161" us="161"/><bf gi="129" ue="163" us="162"/><bf gi="455" ue="164" us="164"/><bf gi="131" ue="165" us="165"/><bf gi="452" ue="166" us="166"/><bf gi="115" ue="167" us="167"/><bf gi="171" ue="168" us="168"/><bf gi="123" ue="169" us="169"/><bf gi="66" ue="170" us="170"/><bf gi="95" ue="171" us="171"/><bf gi="152" ue="172" us="172"/><bf gi="100" ue="173" us="173"/><bf gi="124" ue="174" us="174"/><bf gi="73" ue="175" us="175"/><bf gi="126" ue="176" us="176"/><bf gi="149" ue="177" us="177"/><bf gi="1202" ue="179" us="178"/><bf gi="69" ue="180" us="180"/><bf gi="224" ue="181" us="181"/><bf gi="116" ue="182" us="182"/><bf gi="105" ue="183" us="183"/><bf gi="78" ue="184" us="184"/><bf gi="1204" ue="185" us="185"/><bf gi="67" ue="186" us="186"/><bf gi="96" ue="187" us="187"/><bf gi="1205" ue="190" us="188"/><bf gi="166" ue="191" us="191"/><bf gi="172" ue="197" us="192"/><bf gi="4" ue="198" us="198"/><bf gi="7" ue="199" us="199"/><bf gi="178" ue="207" us="200"/><bf gi="226" ue="208" us="208"/><bf gi="186" ue="214" us="209"/><bf gi="517" ue="215" us="215"/><bf gi="20" ue="216" us="216"/><bf gi="192" ue="220" us="217"/><bf gi="1973" ue="221" us="221"/><bf gi="233" ue="222" us="222"/><bf gi="58" ue="223" us="223"/><bf gi="197" ue="229" us="224"/><bf gi="34" ue="230" us="230"/><bf gi="37" ue="231" us="231"/><bf gi="203" ue="239" us="232"/><bf gi="244" ue="240" us="240"/><bf gi="211" ue="246" us="241"/><bf gi="143" ue="247" us="247"/><bf gi="52" ue="248" us="248"/><bf gi="217" ue="252" us="249"/><bf gi="2312" ue="253" us="253"/><bf gi="285" ue="254" us="254"/><bf gi="221" ue="255" us="255"/><bf gi="1659" ue="256" us="256"/><bf gi="1999" ue="257" us="257"/><bf gi="1660" ue="258" us="258"/><bf gi="2000" ue="259" us="259"/><bf gi="225" ue="260" us="260"/><bf gi="237" ue="261" us="261"/><bf gi="1717" ue="262" us="262"/><bf gi="2033" ue="263" us="263"/><bf gi="1718" ue="264" us="264"/><bf gi="2034" ue="265" us="265"/><bf gi="1720" ue="266" us="266"/><bf gi="2036" ue="267" us="267"/><bf gi="1719" ue="268" us="268"/><bf gi="2035" ue="269" us="269"/><bf gi="1725" ue="270" us="270"/><bf gi="242" ue="271" us="271"/><bf gi="1732" ue="272" us="272"/><bf gi="243" ue="273" us="273"/><bf gi="1735" ue="274" us="274"/><bf gi="2049" ue="275" us="275"/><bf gi="1736" ue="276" us="276"/><bf gi="2050" ue="277" us="277"/><bf gi="1737" ue="278" us="278"/><bf gi="2051" ue="279" us="279"/><bf gi="227" ue="280" us="280"/><bf gi="245" ue="281" us="281"/><bf gi="1734" ue="282" us="282"/><bf gi="2048" ue="283" us="283"/><bf gi="1770" ue="284" us="284"/><bf gi="2092" ue="285" us="285"/><bf gi="1771" ue="286" us="286"/><bf gi="2093" ue="287" us="287"/><bf gi="1772" ue="288" us="288"/><bf gi="2094" ue="289" us="289"/><bf gi="1773" ue="290" us="290"/><bf gi="2095" ue="291" us="291"/><bf gi="1777" ue="292" us="292"/><bf gi="276Line truncated
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Lato-Bold</font-name><full-name>Lato Bold</full-name><family-name>Lato</family-name><embed/><cap-height>723</cap-height><x-height>513</x-height><ascender>805</ascender><descender>-195</descender><bbox><left>-603</left><bottom>-285</bottom><right>1344</right><top>1099</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="1" ue="0" us="0"/><bf gi="171" ue="13" us="13"/><bf gi="2" ue="32" us="32"/><bf gi="82" ue="33" us="33"/><bf gi="122" ue="34" us="34"/><bf gi="134" ue="35" us="35"/><bf gi="130" ue="36" us="36"/><bf gi="166" ue="37" us="37"/><bf gi="123" ue="38" us="38"/><bf gi="121" ue="39" us="39"/><bf gi="108" ue="41" us="40"/><bf gi="114" ue="42" us="42"/><bf gi="144" ue="43" us="43"/><bf gi="84" ue="44" us="44"/><bf gi="102" ue="45" us="45"/><bf gi="87" ue="46" us="46"/><bf gi="99" ue="47" us="47"/><bf gi="135" ue="53" us="48"/><bf gi="164" ue="54" us="54"/><bf gi="141" ue="55" us="55"/><bf gi="165" ue="56" us="56"/><bf gi="142" ue="57" us="57"/><bf gi="86" ue="58" us="58"/><bf gi="85" ue="59" us="59"/><bf gi="149" ue="60" us="60"/><bf gi="146" ue="61" us="61"/><bf gi="150" ue="62" us="62"/><bf gi="83" ue="63" us="63"/><bf gi="124" ue="64" us="64"/><bf gi="3" ue="65" us="65"/><bf gi="5" ue="67" us="66"/><bf gi="8" ue="79" us="68"/><bf gi="22" ue="90" us="80"/><bf gi="110" ue="91" us="91"/><bf gi="101" ue="92" us="92"/><bf gi="111" ue="93" us="93"/><bf gi="119" ue="94" us="94"/><bf gi="105" ue="95" us="95"/><bf gi="68" ue="96" us="96"/><bf gi="33" ue="97" us="97"/><bf gi="35" ue="99" us="98"/><bf gi="38" ue="102" us="100"/><bf gi="43" ue="105" us="103"/><bf gi="47" ue="107" us="106"/><bf gi="163" ue="108" us="108"/><bf gi="49" ue="111" us="109"/><bf gi="54" ue="115" us="112"/><bf gi="59" ue="122" us="116"/><bf gi="112" ue="123" us="123"/><bf gi="100" ue="124" us="124"/><bf gi="113" ue="125" us="125"/><bf gi="120" ue="126" us="126"/><bf gi="2" ue="160" us="160"/><bf gi="167" ue="161" us="161"/><bf gi="131" ue="163" us="162"/><bf gi="455" ue="164" us="164"/><bf gi="133" ue="165" us="165"/><bf gi="452" ue="166" us="166"/><bf gi="117" ue="167" us="167"/><bf gi="73" ue="168" us="168"/><bf gi="125" ue="169" us="169"/><bf gi="66" ue="170" us="170"/><bf gi="97" ue="171" us="171"/><bf gi="154" ue="172" us="172"/><bf gi="102" ue="173" us="173"/><bf gi="126" ue="174" us="174"/><bf gi="74" ue="175" us="175"/><bf gi="128" ue="176" us="176"/><bf gi="151" ue="177" us="177"/><bf gi="1202" ue="179" us="178"/><bf gi="69" ue="180" us="180"/><bf gi="224" ue="181" us="181"/><bf gi="118" ue="182" us="182"/><bf gi="107" ue="183" us="183"/><bf gi="79" ue="184" us="184"/><bf gi="1204" ue="185" us="185"/><bf gi="67" ue="186" us="186"/><bf gi="98" ue="187" us="187"/><bf gi="1205" ue="190" us="188"/><bf gi="168" ue="191" us="191"/><bf gi="172" ue="197" us="192"/><bf gi="4" ue="198" us="198"/><bf gi="7" ue="199" us="199"/><bf gi="178" ue="207" us="200"/><bf gi="226" ue="208" us="208"/><bf gi="186" ue="214" us="209"/><bf gi="517" ue="215" us="215"/><bf gi="20" ue="216" us="216"/><bf gi="192" ue="220" us="217"/><bf gi="2203" ue="221" us="221"/><bf gi="233" ue="222" us="222"/><bf gi="58" ue="223" us="223"/><bf gi="197" ue="229" us="224"/><bf gi="34" ue="230" us="230"/><bf gi="37" ue="231" us="231"/><bf gi="203" ue="239" us="232"/><bf gi="244" ue="240" us="240"/><bf gi="211" ue="246" us="241"/><bf gi="145" ue="247" us="247"/><bf gi="52" ue="248" us="248"/><bf gi="217" ue="252" us="249"/><bf gi="2538" ue="253" us="253"/><bf gi="285" ue="254" us="254"/><bf gi="221" ue="255" us="255"/><bf gi="1889" ue="256" us="256"/><bf gi="2229" ue="257" us="257"/><bf gi="1890" ue="258" us="258"/><bf gi="2230" ue="259" us="259"/><bf gi="225" ue="260" us="260"/><bf gi="237" ue="261" us="261"/><bf gi="1947" ue="262" us="262"/><bf gi="2263" ue="263" us="263"/><bf gi="1948" ue="264" us="264"/><bf gi="2264" ue="265" us="265"/><bf gi="1950" ue="266" us="266"/><bf gi="2266" ue="267" us="267"/><bf gi="1949" ue="268" us="268"/><bf gi="2265" ue="269" us="269"/><bf gi="1955" ue="270" us="270"/><bf gi="242" ue="271" us="271"/><bf gi="1962" ue="272" us="272"/><bf gi="243" ue="273" us="273"/><bf gi="1965" ue="274" us="274"/><bf gi="2279" ue="275" us="275"/><bf gi="1966" ue="276" us="276"/><bf gi="2280" ue="277" us="277"/><bf gi="1967" ue="278" us="278"/><bf gi="2281" ue="279" us="279"/><bf gi="227" ue="280" us="280"/><bf gi="245" ue="281" us="281"/><bf gi="1964" ue="282" us="282"/><bf gi="2278" ue="283" us="283"/><bf gi="2000" ue="284" us="284"/><bf gi="2322" ue="285" us="285"/><bf gi="2001" ue="286" us="286"/><bf gi="2323" ue="287" us="287"/><bf gi="2002" ue="288" us="288"/><bf gi="2324" ue="289" us="289"/><bf gi="2003" ue="290" us="290"/><bf gi="2325" ue="291" us="291"/><bf gi="2007" ue="292" us="292"/><bf gi="276" ue="293" us="2Line truncated
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Lato-BoldItalic</font-name><full-name>Lato Bold Italic</full-name><family-name>Lato</family-name><embed/><cap-height>723</cap-height><x-height>513</x-height><ascender>805</ascender><descender>-195</descender><bbox><left>-520</left><bottom>-283</bottom><right>1293</right><top>1097</top></bbox><flags>97</flags><stemv>0</stemv><italicangle>-7</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="1" ue="0" us="0"/><bf gi="169" ue="13" us="13"/><bf gi="2" ue="32" us="32"/><bf gi="81" ue="33" us="33"/><bf gi="120" ue="34" us="34"/><bf gi="132" ue="35" us="35"/><bf gi="128" ue="36" us="36"/><bf gi="164" ue="37" us="37"/><bf gi="121" ue="38" us="38"/><bf gi="119" ue="39" us="39"/><bf gi="106" ue="41" us="40"/><bf gi="112" ue="42" us="42"/><bf gi="142" ue="43" us="43"/><bf gi="83" ue="44" us="44"/><bf gi="100" ue="45" us="45"/><bf gi="85" ue="46" us="46"/><bf gi="97" ue="47" us="47"/><bf gi="133" ue="53" us="48"/><bf gi="162" ue="54" us="54"/><bf gi="139" ue="55" us="55"/><bf gi="163" ue="56" us="56"/><bf gi="140" ue="57" us="57"/><bf gi="170" ue="58" us="58"/><bf gi="84" ue="59" us="59"/><bf gi="147" ue="60" us="60"/><bf gi="144" ue="61" us="61"/><bf gi="148" ue="62" us="62"/><bf gi="82" ue="63" us="63"/><bf gi="122" ue="64" us="64"/><bf gi="3" ue="65" us="65"/><bf gi="5" ue="67" us="66"/><bf gi="8" ue="79" us="68"/><bf gi="22" ue="90" us="80"/><bf gi="108" ue="91" us="91"/><bf gi="99" ue="92" us="92"/><bf gi="109" ue="93" us="93"/><bf gi="117" ue="94" us="94"/><bf gi="103" ue="95" us="95"/><bf gi="68" ue="96" us="96"/><bf gi="33" ue="97" us="97"/><bf gi="35" ue="99" us="98"/><bf gi="38" ue="102" us="100"/><bf gi="43" ue="105" us="103"/><bf gi="47" ue="107" us="106"/><bf gi="161" ue="108" us="108"/><bf gi="49" ue="111" us="109"/><bf gi="54" ue="115" us="112"/><bf gi="59" ue="122" us="116"/><bf gi="110" ue="123" us="123"/><bf gi="98" ue="124" us="124"/><bf gi="111" ue="125" us="125"/><bf gi="118" ue="126" us="126"/><bf gi="2" ue="160" us="160"/><bf gi="165" ue="161" us="161"/><bf gi="129" ue="163" us="162"/><bf gi="455" ue="164" us="164"/><bf gi="131" ue="165" us="165"/><bf gi="452" ue="166" us="166"/><bf gi="115" ue="167" us="167"/><bf gi="171" ue="168" us="168"/><bf gi="123" ue="169" us="169"/><bf gi="66" ue="170" us="170"/><bf gi="95" ue="171" us="171"/><bf gi="152" ue="172" us="172"/><bf gi="100" ue="173" us="173"/><bf gi="124" ue="174" us="174"/><bf gi="73" ue="175" us="175"/><bf gi="126" ue="176" us="176"/><bf gi="149" ue="177" us="177"/><bf gi="1202" ue="179" us="178"/><bf gi="69" ue="180" us="180"/><bf gi="224" ue="181" us="181"/><bf gi="116" ue="182" us="182"/><bf gi="105" ue="183" us="183"/><bf gi="78" ue="184" us="184"/><bf gi="1204" ue="185" us="185"/><bf gi="67" ue="186" us="186"/><bf gi="96" ue="187" us="187"/><bf gi="1205" ue="190" us="188"/><bf gi="166" ue="191" us="191"/><bf gi="172" ue="197" us="192"/><bf gi="4" ue="198" us="198"/><bf gi="7" ue="199" us="199"/><bf gi="178" ue="207" us="200"/><bf gi="226" ue="208" us="208"/><bf gi="186" ue="214" us="209"/><bf gi="517" ue="215" us="215"/><bf gi="20" ue="216" us="216"/><bf gi="192" ue="220" us="217"/><bf gi="1973" ue="221" us="221"/><bf gi="233" ue="222" us="222"/><bf gi="58" ue="223" us="223"/><bf gi="197" ue="229" us="224"/><bf gi="34" ue="230" us="230"/><bf gi="37" ue="231" us="231"/><bf gi="203" ue="239" us="232"/><bf gi="244" ue="240" us="240"/><bf gi="211" ue="246" us="241"/><bf gi="143" ue="247" us="247"/><bf gi="52" ue="248" us="248"/><bf gi="217" ue="252" us="249"/><bf gi="2312" ue="253" us="253"/><bf gi="285" ue="254" us="254"/><bf gi="221" ue="255" us="255"/><bf gi="1659" ue="256" us="256"/><bf gi="1999" ue="257" us="257"/><bf gi="1660" ue="258" us="258"/><bf gi="2000" ue="259" us="259"/><bf gi="225" ue="260" us="260"/><bf gi="237" ue="261" us="261"/><bf gi="1717" ue="262" us="262"/><bf gi="2033" ue="263" us="263"/><bf gi="1718" ue="264" us="264"/><bf gi="2034" ue="265" us="265"/><bf gi="1720" ue="266" us="266"/><bf gi="2036" ue="267" us="267"/><bf gi="1719" ue="268" us="268"/><bf gi="2035" ue="269" us="269"/><bf gi="1725" ue="270" us="270"/><bf gi="242" ue="271" us="271"/><bf gi="1732" ue="272" us="272"/><bf gi="243" ue="273" us="273"/><bf gi="1735" ue="274" us="274"/><bf gi="2049" ue="275" us="275"/><bf gi="1736" ue="276" us="276"/><bf gi="2050" ue="277" us="277"/><bf gi="1737" ue="278" us="278"/><bf gi="2051" ue="279" us="279"/><bf gi="227" ue="280" us="280"/><bf gi="245" ue="281" us="281"/><bf gi="1734" ue="282" us="282"/><bf gi="2048" ue="283" us="283"/><bf gi="1770" ue="284" us="284"/><bf gi="2092" ue="285" us="285"/><bf gi="1771" ue="286" us="286"/><bf gi="2093" ue="287" us="287"/><bf gi="1772" ue="288" us="288"/><bf gi="2094" ue="289" us="289"/><bf gi="1773" ue="290" us="290"/><bf gi="2095" ue="291" us="291"/><bf gi="1777" ue="292" us="292"/><bf gi="276" Line truncated
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Lato-Hairline</font-name><full-name>Lato Hairline</full-name><family-name>Lato</family-name><embed/><cap-height>700</cap-height><x-height>490</x-height><ascender>805</ascender><descender>-195</descender><bbox><left>-459</left><bottom>-259</bottom><right>1340</right><top>1034</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="1" ue="0" us="0"/><bf gi="171" ue="13" us="13"/><bf gi="2" ue="32" us="32"/><bf gi="82" ue="33" us="33"/><bf gi="122" ue="34" us="34"/><bf gi="134" ue="35" us="35"/><bf gi="130" ue="36" us="36"/><bf gi="166" ue="37" us="37"/><bf gi="123" ue="38" us="38"/><bf gi="121" ue="39" us="39"/><bf gi="108" ue="41" us="40"/><bf gi="114" ue="42" us="42"/><bf gi="144" ue="43" us="43"/><bf gi="84" ue="44" us="44"/><bf gi="102" ue="45" us="45"/><bf gi="87" ue="46" us="46"/><bf gi="99" ue="47" us="47"/><bf gi="135" ue="53" us="48"/><bf gi="164" ue="54" us="54"/><bf gi="141" ue="55" us="55"/><bf gi="165" ue="56" us="56"/><bf gi="142" ue="57" us="57"/><bf gi="86" ue="58" us="58"/><bf gi="85" ue="59" us="59"/><bf gi="149" ue="60" us="60"/><bf gi="146" ue="61" us="61"/><bf gi="150" ue="62" us="62"/><bf gi="83" ue="63" us="63"/><bf gi="124" ue="64" us="64"/><bf gi="3" ue="65" us="65"/><bf gi="5" ue="67" us="66"/><bf gi="8" ue="79" us="68"/><bf gi="22" ue="90" us="80"/><bf gi="110" ue="91" us="91"/><bf gi="101" ue="92" us="92"/><bf gi="111" ue="93" us="93"/><bf gi="119" ue="94" us="94"/><bf gi="105" ue="95" us="95"/><bf gi="68" ue="96" us="96"/><bf gi="33" ue="97" us="97"/><bf gi="35" ue="99" us="98"/><bf gi="38" ue="102" us="100"/><bf gi="43" ue="105" us="103"/><bf gi="47" ue="107" us="106"/><bf gi="163" ue="108" us="108"/><bf gi="49" ue="111" us="109"/><bf gi="54" ue="115" us="112"/><bf gi="59" ue="122" us="116"/><bf gi="112" ue="123" us="123"/><bf gi="100" ue="124" us="124"/><bf gi="113" ue="125" us="125"/><bf gi="120" ue="126" us="126"/><bf gi="2" ue="160" us="160"/><bf gi="167" ue="161" us="161"/><bf gi="131" ue="163" us="162"/><bf gi="455" ue="164" us="164"/><bf gi="133" ue="165" us="165"/><bf gi="452" ue="166" us="166"/><bf gi="117" ue="167" us="167"/><bf gi="73" ue="168" us="168"/><bf gi="125" ue="169" us="169"/><bf gi="66" ue="170" us="170"/><bf gi="97" ue="171" us="171"/><bf gi="154" ue="172" us="172"/><bf gi="102" ue="173" us="173"/><bf gi="126" ue="174" us="174"/><bf gi="74" ue="175" us="175"/><bf gi="128" ue="176" us="176"/><bf gi="151" ue="177" us="177"/><bf gi="1202" ue="179" us="178"/><bf gi="69" ue="180" us="180"/><bf gi="224" ue="181" us="181"/><bf gi="118" ue="182" us="182"/><bf gi="107" ue="183" us="183"/><bf gi="79" ue="184" us="184"/><bf gi="1204" ue="185" us="185"/><bf gi="67" ue="186" us="186"/><bf gi="98" ue="187" us="187"/><bf gi="1205" ue="190" us="188"/><bf gi="168" ue="191" us="191"/><bf gi="172" ue="197" us="192"/><bf gi="4" ue="198" us="198"/><bf gi="7" ue="199" us="199"/><bf gi="178" ue="207" us="200"/><bf gi="226" ue="208" us="208"/><bf gi="186" ue="214" us="209"/><bf gi="517" ue="215" us="215"/><bf gi="20" ue="216" us="216"/><bf gi="192" ue="220" us="217"/><bf gi="2203" ue="221" us="221"/><bf gi="233" ue="222" us="222"/><bf gi="58" ue="223" us="223"/><bf gi="197" ue="229" us="224"/><bf gi="34" ue="230" us="230"/><bf gi="37" ue="231" us="231"/><bf gi="203" ue="239" us="232"/><bf gi="244" ue="240" us="240"/><bf gi="211" ue="246" us="241"/><bf gi="145" ue="247" us="247"/><bf gi="52" ue="248" us="248"/><bf gi="217" ue="252" us="249"/><bf gi="2538" ue="253" us="253"/><bf gi="285" ue="254" us="254"/><bf gi="221" ue="255" us="255"/><bf gi="1889" ue="256" us="256"/><bf gi="2229" ue="257" us="257"/><bf gi="1890" ue="258" us="258"/><bf gi="2230" ue="259" us="259"/><bf gi="225" ue="260" us="260"/><bf gi="237" ue="261" us="261"/><bf gi="1947" ue="262" us="262"/><bf gi="2263" ue="263" us="263"/><bf gi="1948" ue="264" us="264"/><bf gi="2264" ue="265" us="265"/><bf gi="1950" ue="266" us="266"/><bf gi="2266" ue="267" us="267"/><bf gi="1949" ue="268" us="268"/><bf gi="2265" ue="269" us="269"/><bf gi="1955" ue="270" us="270"/><bf gi="242" ue="271" us="271"/><bf gi="1962" ue="272" us="272"/><bf gi="243" ue="273" us="273"/><bf gi="1965" ue="274" us="274"/><bf gi="2279" ue="275" us="275"/><bf gi="1966" ue="276" us="276"/><bf gi="2280" ue="277" us="277"/><bf gi="1967" ue="278" us="278"/><bf gi="2281" ue="279" us="279"/><bf gi="227" ue="280" us="280"/><bf gi="245" ue="281" us="281"/><bf gi="1964" ue="282" us="282"/><bf gi="2278" ue="283" us="283"/><bf gi="2000" ue="284" us="284"/><bf gi="2322" ue="285" us="285"/><bf gi="2001" ue="286" us="286"/><bf gi="2323" ue="287" us="287"/><bf gi="2002" ue="288" us="288"/><bf gi="2324" ue="289" us="289"/><bf gi="2003" ue="290" us="290"/><bf gi="2325" ue="291" us="291"/><bf gi="2007" ue="292" us="292"/><bf gi="276" ue="29Line truncated
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Lato-HairlineItalic</font-name><full-name>Lato Hairline Italic</full-name><family-name>Lato</family-name><embed/><cap-height>700</cap-height><x-height>490</x-height><ascender>805</ascender><descender>-195</descender><bbox><left>-459</left><bottom>-259</bottom><right>1286</right><top>1034</top></bbox><flags>97</flags><stemv>0</stemv><italicangle>-7</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="1" ue="0" us="0"/><bf gi="169" ue="13" us="13"/><bf gi="2" ue="32" us="32"/><bf gi="81" ue="33" us="33"/><bf gi="120" ue="34" us="34"/><bf gi="132" ue="35" us="35"/><bf gi="128" ue="36" us="36"/><bf gi="164" ue="37" us="37"/><bf gi="121" ue="38" us="38"/><bf gi="119" ue="39" us="39"/><bf gi="106" ue="41" us="40"/><bf gi="112" ue="42" us="42"/><bf gi="142" ue="43" us="43"/><bf gi="83" ue="44" us="44"/><bf gi="100" ue="45" us="45"/><bf gi="85" ue="46" us="46"/><bf gi="97" ue="47" us="47"/><bf gi="133" ue="53" us="48"/><bf gi="162" ue="54" us="54"/><bf gi="139" ue="55" us="55"/><bf gi="163" ue="56" us="56"/><bf gi="140" ue="57" us="57"/><bf gi="170" ue="58" us="58"/><bf gi="84" ue="59" us="59"/><bf gi="147" ue="60" us="60"/><bf gi="144" ue="61" us="61"/><bf gi="148" ue="62" us="62"/><bf gi="82" ue="63" us="63"/><bf gi="122" ue="64" us="64"/><bf gi="3" ue="65" us="65"/><bf gi="5" ue="67" us="66"/><bf gi="8" ue="79" us="68"/><bf gi="22" ue="90" us="80"/><bf gi="108" ue="91" us="91"/><bf gi="99" ue="92" us="92"/><bf gi="109" ue="93" us="93"/><bf gi="117" ue="94" us="94"/><bf gi="103" ue="95" us="95"/><bf gi="68" ue="96" us="96"/><bf gi="33" ue="97" us="97"/><bf gi="35" ue="99" us="98"/><bf gi="38" ue="102" us="100"/><bf gi="43" ue="105" us="103"/><bf gi="47" ue="107" us="106"/><bf gi="161" ue="108" us="108"/><bf gi="49" ue="111" us="109"/><bf gi="54" ue="115" us="112"/><bf gi="59" ue="122" us="116"/><bf gi="110" ue="123" us="123"/><bf gi="98" ue="124" us="124"/><bf gi="111" ue="125" us="125"/><bf gi="118" ue="126" us="126"/><bf gi="2" ue="160" us="160"/><bf gi="165" ue="161" us="161"/><bf gi="129" ue="163" us="162"/><bf gi="455" ue="164" us="164"/><bf gi="131" ue="165" us="165"/><bf gi="452" ue="166" us="166"/><bf gi="115" ue="167" us="167"/><bf gi="171" ue="168" us="168"/><bf gi="123" ue="169" us="169"/><bf gi="66" ue="170" us="170"/><bf gi="95" ue="171" us="171"/><bf gi="152" ue="172" us="172"/><bf gi="100" ue="173" us="173"/><bf gi="124" ue="174" us="174"/><bf gi="73" ue="175" us="175"/><bf gi="126" ue="176" us="176"/><bf gi="149" ue="177" us="177"/><bf gi="1202" ue="179" us="178"/><bf gi="69" ue="180" us="180"/><bf gi="224" ue="181" us="181"/><bf gi="116" ue="182" us="182"/><bf gi="105" ue="183" us="183"/><bf gi="78" ue="184" us="184"/><bf gi="1204" ue="185" us="185"/><bf gi="67" ue="186" us="186"/><bf gi="96" ue="187" us="187"/><bf gi="1205" ue="190" us="188"/><bf gi="166" ue="191" us="191"/><bf gi="172" ue="197" us="192"/><bf gi="4" ue="198" us="198"/><bf gi="7" ue="199" us="199"/><bf gi="178" ue="207" us="200"/><bf gi="226" ue="208" us="208"/><bf gi="186" ue="214" us="209"/><bf gi="517" ue="215" us="215"/><bf gi="20" ue="216" us="216"/><bf gi="192" ue="220" us="217"/><bf gi="1973" ue="221" us="221"/><bf gi="233" ue="222" us="222"/><bf gi="58" ue="223" us="223"/><bf gi="197" ue="229" us="224"/><bf gi="34" ue="230" us="230"/><bf gi="37" ue="231" us="231"/><bf gi="203" ue="239" us="232"/><bf gi="244" ue="240" us="240"/><bf gi="211" ue="246" us="241"/><bf gi="143" ue="247" us="247"/><bf gi="52" ue="248" us="248"/><bf gi="217" ue="252" us="249"/><bf gi="2312" ue="253" us="253"/><bf gi="285" ue="254" us="254"/><bf gi="221" ue="255" us="255"/><bf gi="1659" ue="256" us="256"/><bf gi="1999" ue="257" us="257"/><bf gi="1660" ue="258" us="258"/><bf gi="2000" ue="259" us="259"/><bf gi="225" ue="260" us="260"/><bf gi="237" ue="261" us="261"/><bf gi="1717" ue="262" us="262"/><bf gi="2033" ue="263" us="263"/><bf gi="1718" ue="264" us="264"/><bf gi="2034" ue="265" us="265"/><bf gi="1720" ue="266" us="266"/><bf gi="2036" ue="267" us="267"/><bf gi="1719" ue="268" us="268"/><bf gi="2035" ue="269" us="269"/><bf gi="1725" ue="270" us="270"/><bf gi="242" ue="271" us="271"/><bf gi="1732" ue="272" us="272"/><bf gi="243" ue="273" us="273"/><bf gi="1735" ue="274" us="274"/><bf gi="2049" ue="275" us="275"/><bf gi="1736" ue="276" us="276"/><bf gi="2050" ue="277" us="277"/><bf gi="1737" ue="278" us="278"/><bf gi="2051" ue="279" us="279"/><bf gi="227" ue="280" us="280"/><bf gi="245" ue="281" us="281"/><bf gi="1734" ue="282" us="282"/><bf gi="2048" ue="283" us="283"/><bf gi="1770" ue="284" us="284"/><bf gi="2092" ue="285" us="285"/><bf gi="1771" ue="286" us="286"/><bf gi="2093" ue="287" us="287"/><bf gi="1772" ue="288" us="288"/><bf gi="2094" ue="289" us="289"/><bf gi="1773" ue="290" us="290"/><bf gi="2095" ue="291" us="291"/><bf gi="1777" ue="292" us="292"/><bf gLine truncated
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Lato-Heavy</font-name><full-name>Lato Heavy</full-name><family-name>Lato</family-name><embed/><cap-height>725</cap-height><x-height>515</x-height><ascender>805</ascender><descender>-195</descender><bbox><left>-626</left><bottom>-291</bottom><right>1345</right><top>1107</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="1" ue="0" us="0"/><bf gi="171" ue="13" us="13"/><bf gi="2" ue="32" us="32"/><bf gi="82" ue="33" us="33"/><bf gi="122" ue="34" us="34"/><bf gi="134" ue="35" us="35"/><bf gi="130" ue="36" us="36"/><bf gi="166" ue="37" us="37"/><bf gi="123" ue="38" us="38"/><bf gi="121" ue="39" us="39"/><bf gi="108" ue="41" us="40"/><bf gi="114" ue="42" us="42"/><bf gi="144" ue="43" us="43"/><bf gi="84" ue="44" us="44"/><bf gi="102" ue="45" us="45"/><bf gi="87" ue="46" us="46"/><bf gi="99" ue="47" us="47"/><bf gi="135" ue="53" us="48"/><bf gi="164" ue="54" us="54"/><bf gi="141" ue="55" us="55"/><bf gi="165" ue="56" us="56"/><bf gi="142" ue="57" us="57"/><bf gi="86" ue="58" us="58"/><bf gi="85" ue="59" us="59"/><bf gi="149" ue="60" us="60"/><bf gi="146" ue="61" us="61"/><bf gi="150" ue="62" us="62"/><bf gi="83" ue="63" us="63"/><bf gi="124" ue="64" us="64"/><bf gi="3" ue="65" us="65"/><bf gi="5" ue="67" us="66"/><bf gi="8" ue="79" us="68"/><bf gi="22" ue="90" us="80"/><bf gi="110" ue="91" us="91"/><bf gi="101" ue="92" us="92"/><bf gi="111" ue="93" us="93"/><bf gi="119" ue="94" us="94"/><bf gi="105" ue="95" us="95"/><bf gi="68" ue="96" us="96"/><bf gi="33" ue="97" us="97"/><bf gi="35" ue="99" us="98"/><bf gi="38" ue="102" us="100"/><bf gi="43" ue="105" us="103"/><bf gi="47" ue="107" us="106"/><bf gi="163" ue="108" us="108"/><bf gi="49" ue="111" us="109"/><bf gi="54" ue="115" us="112"/><bf gi="59" ue="122" us="116"/><bf gi="112" ue="123" us="123"/><bf gi="100" ue="124" us="124"/><bf gi="113" ue="125" us="125"/><bf gi="120" ue="126" us="126"/><bf gi="2" ue="160" us="160"/><bf gi="167" ue="161" us="161"/><bf gi="131" ue="163" us="162"/><bf gi="455" ue="164" us="164"/><bf gi="133" ue="165" us="165"/><bf gi="452" ue="166" us="166"/><bf gi="117" ue="167" us="167"/><bf gi="73" ue="168" us="168"/><bf gi="125" ue="169" us="169"/><bf gi="66" ue="170" us="170"/><bf gi="97" ue="171" us="171"/><bf gi="154" ue="172" us="172"/><bf gi="102" ue="173" us="173"/><bf gi="126" ue="174" us="174"/><bf gi="74" ue="175" us="175"/><bf gi="128" ue="176" us="176"/><bf gi="151" ue="177" us="177"/><bf gi="1202" ue="179" us="178"/><bf gi="69" ue="180" us="180"/><bf gi="224" ue="181" us="181"/><bf gi="118" ue="182" us="182"/><bf gi="107" ue="183" us="183"/><bf gi="79" ue="184" us="184"/><bf gi="1204" ue="185" us="185"/><bf gi="67" ue="186" us="186"/><bf gi="98" ue="187" us="187"/><bf gi="1205" ue="190" us="188"/><bf gi="168" ue="191" us="191"/><bf gi="172" ue="197" us="192"/><bf gi="4" ue="198" us="198"/><bf gi="7" ue="199" us="199"/><bf gi="178" ue="207" us="200"/><bf gi="226" ue="208" us="208"/><bf gi="186" ue="214" us="209"/><bf gi="517" ue="215" us="215"/><bf gi="20" ue="216" us="216"/><bf gi="192" ue="220" us="217"/><bf gi="2203" ue="221" us="221"/><bf gi="233" ue="222" us="222"/><bf gi="58" ue="223" us="223"/><bf gi="197" ue="229" us="224"/><bf gi="34" ue="230" us="230"/><bf gi="37" ue="231" us="231"/><bf gi="203" ue="239" us="232"/><bf gi="244" ue="240" us="240"/><bf gi="211" ue="246" us="241"/><bf gi="145" ue="247" us="247"/><bf gi="52" ue="248" us="248"/><bf gi="217" ue="252" us="249"/><bf gi="2538" ue="253" us="253"/><bf gi="285" ue="254" us="254"/><bf gi="221" ue="255" us="255"/><bf gi="1889" ue="256" us="256"/><bf gi="2229" ue="257" us="257"/><bf gi="1890" ue="258" us="258"/><bf gi="2230" ue="259" us="259"/><bf gi="225" ue="260" us="260"/><bf gi="237" ue="261" us="261"/><bf gi="1947" ue="262" us="262"/><bf gi="2263" ue="263" us="263"/><bf gi="1948" ue="264" us="264"/><bf gi="2264" ue="265" us="265"/><bf gi="1950" ue="266" us="266"/><bf gi="2266" ue="267" us="267"/><bf gi="1949" ue="268" us="268"/><bf gi="2265" ue="269" us="269"/><bf gi="1955" ue="270" us="270"/><bf gi="242" ue="271" us="271"/><bf gi="1962" ue="272" us="272"/><bf gi="243" ue="273" us="273"/><bf gi="1965" ue="274" us="274"/><bf gi="2279" ue="275" us="275"/><bf gi="1966" ue="276" us="276"/><bf gi="2280" ue="277" us="277"/><bf gi="1967" ue="278" us="278"/><bf gi="2281" ue="279" us="279"/><bf gi="227" ue="280" us="280"/><bf gi="245" ue="281" us="281"/><bf gi="1964" ue="282" us="282"/><bf gi="2278" ue="283" us="283"/><bf gi="2000" ue="284" us="284"/><bf gi="2322" ue="285" us="285"/><bf gi="2001" ue="286" us="286"/><bf gi="2323" ue="287" us="287"/><bf gi="2002" ue="288" us="288"/><bf gi="2324" ue="289" us="289"/><bf gi="2003" ue="290" us="290"/><bf gi="2325" ue="291" us="291"/><bf gi="2007" ue="292" us="292"/><bf gi="276" ue="293" us=Line truncated
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Lato-HeavyItalic</font-name><full-name>Lato Heavy Italic</full-name><family-name>Lato</family-name><embed/><cap-height>725</cap-height><x-height>515</x-height><ascender>805</ascender><descender>-195</descender><bbox><left>-528</left><bottom>-289</bottom><right>1294</right><top>1105</top></bbox><flags>97</flags><stemv>0</stemv><italicangle>-7</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="1" ue="0" us="0"/><bf gi="169" ue="13" us="13"/><bf gi="2" ue="32" us="32"/><bf gi="81" ue="33" us="33"/><bf gi="120" ue="34" us="34"/><bf gi="132" ue="35" us="35"/><bf gi="128" ue="36" us="36"/><bf gi="164" ue="37" us="37"/><bf gi="121" ue="38" us="38"/><bf gi="119" ue="39" us="39"/><bf gi="106" ue="41" us="40"/><bf gi="112" ue="42" us="42"/><bf gi="142" ue="43" us="43"/><bf gi="83" ue="44" us="44"/><bf gi="100" ue="45" us="45"/><bf gi="85" ue="46" us="46"/><bf gi="97" ue="47" us="47"/><bf gi="133" ue="53" us="48"/><bf gi="162" ue="54" us="54"/><bf gi="139" ue="55" us="55"/><bf gi="163" ue="56" us="56"/><bf gi="140" ue="57" us="57"/><bf gi="170" ue="58" us="58"/><bf gi="84" ue="59" us="59"/><bf gi="147" ue="60" us="60"/><bf gi="144" ue="61" us="61"/><bf gi="148" ue="62" us="62"/><bf gi="82" ue="63" us="63"/><bf gi="122" ue="64" us="64"/><bf gi="3" ue="65" us="65"/><bf gi="5" ue="67" us="66"/><bf gi="8" ue="79" us="68"/><bf gi="22" ue="90" us="80"/><bf gi="108" ue="91" us="91"/><bf gi="99" ue="92" us="92"/><bf gi="109" ue="93" us="93"/><bf gi="117" ue="94" us="94"/><bf gi="103" ue="95" us="95"/><bf gi="68" ue="96" us="96"/><bf gi="33" ue="97" us="97"/><bf gi="35" ue="99" us="98"/><bf gi="38" ue="102" us="100"/><bf gi="43" ue="105" us="103"/><bf gi="47" ue="107" us="106"/><bf gi="161" ue="108" us="108"/><bf gi="49" ue="111" us="109"/><bf gi="54" ue="115" us="112"/><bf gi="59" ue="122" us="116"/><bf gi="110" ue="123" us="123"/><bf gi="98" ue="124" us="124"/><bf gi="111" ue="125" us="125"/><bf gi="118" ue="126" us="126"/><bf gi="2" ue="160" us="160"/><bf gi="165" ue="161" us="161"/><bf gi="129" ue="163" us="162"/><bf gi="455" ue="164" us="164"/><bf gi="131" ue="165" us="165"/><bf gi="452" ue="166" us="166"/><bf gi="115" ue="167" us="167"/><bf gi="171" ue="168" us="168"/><bf gi="123" ue="169" us="169"/><bf gi="66" ue="170" us="170"/><bf gi="95" ue="171" us="171"/><bf gi="152" ue="172" us="172"/><bf gi="100" ue="173" us="173"/><bf gi="124" ue="174" us="174"/><bf gi="73" ue="175" us="175"/><bf gi="126" ue="176" us="176"/><bf gi="149" ue="177" us="177"/><bf gi="1202" ue="179" us="178"/><bf gi="69" ue="180" us="180"/><bf gi="224" ue="181" us="181"/><bf gi="116" ue="182" us="182"/><bf gi="105" ue="183" us="183"/><bf gi="78" ue="184" us="184"/><bf gi="1204" ue="185" us="185"/><bf gi="67" ue="186" us="186"/><bf gi="96" ue="187" us="187"/><bf gi="1205" ue="190" us="188"/><bf gi="166" ue="191" us="191"/><bf gi="172" ue="197" us="192"/><bf gi="4" ue="198" us="198"/><bf gi="7" ue="199" us="199"/><bf gi="178" ue="207" us="200"/><bf gi="226" ue="208" us="208"/><bf gi="186" ue="214" us="209"/><bf gi="517" ue="215" us="215"/><bf gi="20" ue="216" us="216"/><bf gi="192" ue="220" us="217"/><bf gi="1973" ue="221" us="221"/><bf gi="233" ue="222" us="222"/><bf gi="58" ue="223" us="223"/><bf gi="197" ue="229" us="224"/><bf gi="34" ue="230" us="230"/><bf gi="37" ue="231" us="231"/><bf gi="203" ue="239" us="232"/><bf gi="244" ue="240" us="240"/><bf gi="211" ue="246" us="241"/><bf gi="143" ue="247" us="247"/><bf gi="52" ue="248" us="248"/><bf gi="217" ue="252" us="249"/><bf gi="2312" ue="253" us="253"/><bf gi="285" ue="254" us="254"/><bf gi="221" ue="255" us="255"/><bf gi="1659" ue="256" us="256"/><bf gi="1999" ue="257" us="257"/><bf gi="1660" ue="258" us="258"/><bf gi="2000" ue="259" us="259"/><bf gi="225" ue="260" us="260"/><bf gi="237" ue="261" us="261"/><bf gi="1717" ue="262" us="262"/><bf gi="2033" ue="263" us="263"/><bf gi="1718" ue="264" us="264"/><bf gi="2034" ue="265" us="265"/><bf gi="1720" ue="266" us="266"/><bf gi="2036" ue="267" us="267"/><bf gi="1719" ue="268" us="268"/><bf gi="2035" ue="269" us="269"/><bf gi="1725" ue="270" us="270"/><bf gi="242" ue="271" us="271"/><bf gi="1732" ue="272" us="272"/><bf gi="243" ue="273" us="273"/><bf gi="1735" ue="274" us="274"/><bf gi="2049" ue="275" us="275"/><bf gi="1736" ue="276" us="276"/><bf gi="2050" ue="277" us="277"/><bf gi="1737" ue="278" us="278"/><bf gi="2051" ue="279" us="279"/><bf gi="227" ue="280" us="280"/><bf gi="245" ue="281" us="281"/><bf gi="1734" ue="282" us="282"/><bf gi="2048" ue="283" us="283"/><bf gi="1770" ue="284" us="284"/><bf gi="2092" ue="285" us="285"/><bf gi="1771" ue="286" us="286"/><bf gi="2093" ue="287" us="287"/><bf gi="1772" ue="288" us="288"/><bf gi="2094" ue="289" us="289"/><bf gi="1773" ue="290" us="290"/><bf gi="2095" ue="291" us="291"/><bf gi="1777" ue="292" us="292"/><bf gi="276Line truncated
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Lato-Italic</font-name><full-name>Lato Italic</full-name><family-name>Lato</family-name><embed/><cap-height>716</cap-height><x-height>506</x-height><ascender>805</ascender><descender>-195</descender><bbox><left>-501</left><bottom>-268</bottom><right>1290</right><top>1077</top></bbox><flags>97</flags><stemv>0</stemv><italicangle>-7</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="1" ue="0" us="0"/><bf gi="169" ue="13" us="13"/><bf gi="2" ue="32" us="32"/><bf gi="81" ue="33" us="33"/><bf gi="120" ue="34" us="34"/><bf gi="132" ue="35" us="35"/><bf gi="128" ue="36" us="36"/><bf gi="164" ue="37" us="37"/><bf gi="121" ue="38" us="38"/><bf gi="119" ue="39" us="39"/><bf gi="106" ue="41" us="40"/><bf gi="112" ue="42" us="42"/><bf gi="142" ue="43" us="43"/><bf gi="83" ue="44" us="44"/><bf gi="100" ue="45" us="45"/><bf gi="85" ue="46" us="46"/><bf gi="97" ue="47" us="47"/><bf gi="133" ue="53" us="48"/><bf gi="162" ue="54" us="54"/><bf gi="139" ue="55" us="55"/><bf gi="163" ue="56" us="56"/><bf gi="140" ue="57" us="57"/><bf gi="170" ue="58" us="58"/><bf gi="84" ue="59" us="59"/><bf gi="147" ue="60" us="60"/><bf gi="144" ue="61" us="61"/><bf gi="148" ue="62" us="62"/><bf gi="82" ue="63" us="63"/><bf gi="122" ue="64" us="64"/><bf gi="3" ue="65" us="65"/><bf gi="5" ue="67" us="66"/><bf gi="8" ue="79" us="68"/><bf gi="22" ue="90" us="80"/><bf gi="108" ue="91" us="91"/><bf gi="99" ue="92" us="92"/><bf gi="109" ue="93" us="93"/><bf gi="117" ue="94" us="94"/><bf gi="103" ue="95" us="95"/><bf gi="68" ue="96" us="96"/><bf gi="33" ue="97" us="97"/><bf gi="35" ue="99" us="98"/><bf gi="38" ue="102" us="100"/><bf gi="43" ue="105" us="103"/><bf gi="47" ue="107" us="106"/><bf gi="161" ue="108" us="108"/><bf gi="49" ue="111" us="109"/><bf gi="54" ue="115" us="112"/><bf gi="59" ue="122" us="116"/><bf gi="110" ue="123" us="123"/><bf gi="98" ue="124" us="124"/><bf gi="111" ue="125" us="125"/><bf gi="118" ue="126" us="126"/><bf gi="2" ue="160" us="160"/><bf gi="165" ue="161" us="161"/><bf gi="129" ue="163" us="162"/><bf gi="455" ue="164" us="164"/><bf gi="131" ue="165" us="165"/><bf gi="452" ue="166" us="166"/><bf gi="115" ue="167" us="167"/><bf gi="171" ue="168" us="168"/><bf gi="123" ue="169" us="169"/><bf gi="66" ue="170" us="170"/><bf gi="95" ue="171" us="171"/><bf gi="152" ue="172" us="172"/><bf gi="100" ue="173" us="173"/><bf gi="124" ue="174" us="174"/><bf gi="73" ue="175" us="175"/><bf gi="126" ue="176" us="176"/><bf gi="149" ue="177" us="177"/><bf gi="1202" ue="179" us="178"/><bf gi="69" ue="180" us="180"/><bf gi="224" ue="181" us="181"/><bf gi="116" ue="182" us="182"/><bf gi="105" ue="183" us="183"/><bf gi="78" ue="184" us="184"/><bf gi="1204" ue="185" us="185"/><bf gi="67" ue="186" us="186"/><bf gi="96" ue="187" us="187"/><bf gi="1205" ue="190" us="188"/><bf gi="166" ue="191" us="191"/><bf gi="172" ue="197" us="192"/><bf gi="4" ue="198" us="198"/><bf gi="7" ue="199" us="199"/><bf gi="178" ue="207" us="200"/><bf gi="226" ue="208" us="208"/><bf gi="186" ue="214" us="209"/><bf gi="517" ue="215" us="215"/><bf gi="20" ue="216" us="216"/><bf gi="192" ue="220" us="217"/><bf gi="1973" ue="221" us="221"/><bf gi="233" ue="222" us="222"/><bf gi="58" ue="223" us="223"/><bf gi="197" ue="229" us="224"/><bf gi="34" ue="230" us="230"/><bf gi="37" ue="231" us="231"/><bf gi="203" ue="239" us="232"/><bf gi="244" ue="240" us="240"/><bf gi="211" ue="246" us="241"/><bf gi="143" ue="247" us="247"/><bf gi="52" ue="248" us="248"/><bf gi="217" ue="252" us="249"/><bf gi="2312" ue="253" us="253"/><bf gi="285" ue="254" us="254"/><bf gi="221" ue="255" us="255"/><bf gi="1659" ue="256" us="256"/><bf gi="1999" ue="257" us="257"/><bf gi="1660" ue="258" us="258"/><bf gi="2000" ue="259" us="259"/><bf gi="225" ue="260" us="260"/><bf gi="237" ue="261" us="261"/><bf gi="1717" ue="262" us="262"/><bf gi="2033" ue="263" us="263"/><bf gi="1718" ue="264" us="264"/><bf gi="2034" ue="265" us="265"/><bf gi="1720" ue="266" us="266"/><bf gi="2036" ue="267" us="267"/><bf gi="1719" ue="268" us="268"/><bf gi="2035" ue="269" us="269"/><bf gi="1725" ue="270" us="270"/><bf gi="242" ue="271" us="271"/><bf gi="1732" ue="272" us="272"/><bf gi="243" ue="273" us="273"/><bf gi="1735" ue="274" us="274"/><bf gi="2049" ue="275" us="275"/><bf gi="1736" ue="276" us="276"/><bf gi="2050" ue="277" us="277"/><bf gi="1737" ue="278" us="278"/><bf gi="2051" ue="279" us="279"/><bf gi="227" ue="280" us="280"/><bf gi="245" ue="281" us="281"/><bf gi="1734" ue="282" us="282"/><bf gi="2048" ue="283" us="283"/><bf gi="1770" ue="284" us="284"/><bf gi="2092" ue="285" us="285"/><bf gi="1771" ue="286" us="286"/><bf gi="2093" ue="287" us="287"/><bf gi="1772" ue="288" us="288"/><bf gi="2094" ue="289" us="289"/><bf gi="1773" ue="290" us="290"/><bf gi="2095" ue="291" us="291"/><bf gi="1777" ue="292" us="292"/><bf gi="276" ue="293" Line truncated
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Lato-Light</font-name><full-name>Lato Light</full-name><family-name>Lato</family-name><embed/><cap-height>707</cap-height><x-height>497</x-height><ascender>805</ascender><descender>-195</descender><bbox><left>-479</left><bottom>-263</bottom><right>1341</right><top>1055</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="1" ue="0" us="0"/><bf gi="171" ue="13" us="13"/><bf gi="2" ue="32" us="32"/><bf gi="82" ue="33" us="33"/><bf gi="122" ue="34" us="34"/><bf gi="134" ue="35" us="35"/><bf gi="130" ue="36" us="36"/><bf gi="166" ue="37" us="37"/><bf gi="123" ue="38" us="38"/><bf gi="121" ue="39" us="39"/><bf gi="108" ue="41" us="40"/><bf gi="114" ue="42" us="42"/><bf gi="144" ue="43" us="43"/><bf gi="84" ue="44" us="44"/><bf gi="102" ue="45" us="45"/><bf gi="87" ue="46" us="46"/><bf gi="99" ue="47" us="47"/><bf gi="135" ue="53" us="48"/><bf gi="164" ue="54" us="54"/><bf gi="141" ue="55" us="55"/><bf gi="165" ue="56" us="56"/><bf gi="142" ue="57" us="57"/><bf gi="86" ue="58" us="58"/><bf gi="85" ue="59" us="59"/><bf gi="149" ue="60" us="60"/><bf gi="146" ue="61" us="61"/><bf gi="150" ue="62" us="62"/><bf gi="83" ue="63" us="63"/><bf gi="124" ue="64" us="64"/><bf gi="3" ue="65" us="65"/><bf gi="5" ue="67" us="66"/><bf gi="8" ue="79" us="68"/><bf gi="22" ue="90" us="80"/><bf gi="110" ue="91" us="91"/><bf gi="101" ue="92" us="92"/><bf gi="111" ue="93" us="93"/><bf gi="119" ue="94" us="94"/><bf gi="105" ue="95" us="95"/><bf gi="68" ue="96" us="96"/><bf gi="33" ue="97" us="97"/><bf gi="35" ue="99" us="98"/><bf gi="38" ue="102" us="100"/><bf gi="43" ue="105" us="103"/><bf gi="47" ue="107" us="106"/><bf gi="163" ue="108" us="108"/><bf gi="49" ue="111" us="109"/><bf gi="54" ue="115" us="112"/><bf gi="59" ue="122" us="116"/><bf gi="112" ue="123" us="123"/><bf gi="100" ue="124" us="124"/><bf gi="113" ue="125" us="125"/><bf gi="120" ue="126" us="126"/><bf gi="2" ue="160" us="160"/><bf gi="167" ue="161" us="161"/><bf gi="131" ue="163" us="162"/><bf gi="455" ue="164" us="164"/><bf gi="133" ue="165" us="165"/><bf gi="452" ue="166" us="166"/><bf gi="117" ue="167" us="167"/><bf gi="73" ue="168" us="168"/><bf gi="125" ue="169" us="169"/><bf gi="66" ue="170" us="170"/><bf gi="97" ue="171" us="171"/><bf gi="154" ue="172" us="172"/><bf gi="102" ue="173" us="173"/><bf gi="126" ue="174" us="174"/><bf gi="74" ue="175" us="175"/><bf gi="128" ue="176" us="176"/><bf gi="151" ue="177" us="177"/><bf gi="1202" ue="179" us="178"/><bf gi="69" ue="180" us="180"/><bf gi="224" ue="181" us="181"/><bf gi="118" ue="182" us="182"/><bf gi="107" ue="183" us="183"/><bf gi="79" ue="184" us="184"/><bf gi="1204" ue="185" us="185"/><bf gi="67" ue="186" us="186"/><bf gi="98" ue="187" us="187"/><bf gi="1205" ue="190" us="188"/><bf gi="168" ue="191" us="191"/><bf gi="172" ue="197" us="192"/><bf gi="4" ue="198" us="198"/><bf gi="7" ue="199" us="199"/><bf gi="178" ue="207" us="200"/><bf gi="226" ue="208" us="208"/><bf gi="186" ue="214" us="209"/><bf gi="517" ue="215" us="215"/><bf gi="20" ue="216" us="216"/><bf gi="192" ue="220" us="217"/><bf gi="2203" ue="221" us="221"/><bf gi="233" ue="222" us="222"/><bf gi="58" ue="223" us="223"/><bf gi="197" ue="229" us="224"/><bf gi="34" ue="230" us="230"/><bf gi="37" ue="231" us="231"/><bf gi="203" ue="239" us="232"/><bf gi="244" ue="240" us="240"/><bf gi="211" ue="246" us="241"/><bf gi="145" ue="247" us="247"/><bf gi="52" ue="248" us="248"/><bf gi="217" ue="252" us="249"/><bf gi="2538" ue="253" us="253"/><bf gi="285" ue="254" us="254"/><bf gi="221" ue="255" us="255"/><bf gi="1889" ue="256" us="256"/><bf gi="2229" ue="257" us="257"/><bf gi="1890" ue="258" us="258"/><bf gi="2230" ue="259" us="259"/><bf gi="225" ue="260" us="260"/><bf gi="237" ue="261" us="261"/><bf gi="1947" ue="262" us="262"/><bf gi="2263" ue="263" us="263"/><bf gi="1948" ue="264" us="264"/><bf gi="2264" ue="265" us="265"/><bf gi="1950" ue="266" us="266"/><bf gi="2266" ue="267" us="267"/><bf gi="1949" ue="268" us="268"/><bf gi="2265" ue="269" us="269"/><bf gi="1955" ue="270" us="270"/><bf gi="242" ue="271" us="271"/><bf gi="1962" ue="272" us="272"/><bf gi="243" ue="273" us="273"/><bf gi="1965" ue="274" us="274"/><bf gi="2279" ue="275" us="275"/><bf gi="1966" ue="276" us="276"/><bf gi="2280" ue="277" us="277"/><bf gi="1967" ue="278" us="278"/><bf gi="2281" ue="279" us="279"/><bf gi="227" ue="280" us="280"/><bf gi="245" ue="281" us="281"/><bf gi="1964" ue="282" us="282"/><bf gi="2278" ue="283" us="283"/><bf gi="2000" ue="284" us="284"/><bf gi="2322" ue="285" us="285"/><bf gi="2001" ue="286" us="286"/><bf gi="2323" ue="287" us="287"/><bf gi="2002" ue="288" us="288"/><bf gi="2324" ue="289" us="289"/><bf gi="2003" ue="290" us="290"/><bf gi="2325" ue="291" us="291"/><bf gi="2007" ue="292" us="292"/><bf gi="276" ue="293" us=Line truncated
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Lato-LightItalic</font-name><full-name>Lato Light Italic</full-name><family-name>Lato</family-name><embed/><cap-height>707</cap-height><x-height>497</x-height><ascender>805</ascender><descender>-195</descender><bbox><left>-479</left><bottom>-263</bottom><right>1288</right><top>1054</top></bbox><flags>97</flags><stemv>0</stemv><italicangle>-7</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="1" ue="0" us="0"/><bf gi="169" ue="13" us="13"/><bf gi="2" ue="32" us="32"/><bf gi="81" ue="33" us="33"/><bf gi="120" ue="34" us="34"/><bf gi="132" ue="35" us="35"/><bf gi="128" ue="36" us="36"/><bf gi="164" ue="37" us="37"/><bf gi="121" ue="38" us="38"/><bf gi="119" ue="39" us="39"/><bf gi="106" ue="41" us="40"/><bf gi="112" ue="42" us="42"/><bf gi="142" ue="43" us="43"/><bf gi="83" ue="44" us="44"/><bf gi="100" ue="45" us="45"/><bf gi="85" ue="46" us="46"/><bf gi="97" ue="47" us="47"/><bf gi="133" ue="53" us="48"/><bf gi="162" ue="54" us="54"/><bf gi="139" ue="55" us="55"/><bf gi="163" ue="56" us="56"/><bf gi="140" ue="57" us="57"/><bf gi="170" ue="58" us="58"/><bf gi="84" ue="59" us="59"/><bf gi="147" ue="60" us="60"/><bf gi="144" ue="61" us="61"/><bf gi="148" ue="62" us="62"/><bf gi="82" ue="63" us="63"/><bf gi="122" ue="64" us="64"/><bf gi="3" ue="65" us="65"/><bf gi="5" ue="67" us="66"/><bf gi="8" ue="79" us="68"/><bf gi="22" ue="90" us="80"/><bf gi="108" ue="91" us="91"/><bf gi="99" ue="92" us="92"/><bf gi="109" ue="93" us="93"/><bf gi="117" ue="94" us="94"/><bf gi="103" ue="95" us="95"/><bf gi="68" ue="96" us="96"/><bf gi="33" ue="97" us="97"/><bf gi="35" ue="99" us="98"/><bf gi="38" ue="102" us="100"/><bf gi="43" ue="105" us="103"/><bf gi="47" ue="107" us="106"/><bf gi="161" ue="108" us="108"/><bf gi="49" ue="111" us="109"/><bf gi="54" ue="115" us="112"/><bf gi="59" ue="122" us="116"/><bf gi="110" ue="123" us="123"/><bf gi="98" ue="124" us="124"/><bf gi="111" ue="125" us="125"/><bf gi="118" ue="126" us="126"/><bf gi="2" ue="160" us="160"/><bf gi="165" ue="161" us="161"/><bf gi="129" ue="163" us="162"/><bf gi="455" ue="164" us="164"/><bf gi="131" ue="165" us="165"/><bf gi="452" ue="166" us="166"/><bf gi="115" ue="167" us="167"/><bf gi="171" ue="168" us="168"/><bf gi="123" ue="169" us="169"/><bf gi="66" ue="170" us="170"/><bf gi="95" ue="171" us="171"/><bf gi="152" ue="172" us="172"/><bf gi="100" ue="173" us="173"/><bf gi="124" ue="174" us="174"/><bf gi="73" ue="175" us="175"/><bf gi="126" ue="176" us="176"/><bf gi="149" ue="177" us="177"/><bf gi="1202" ue="179" us="178"/><bf gi="69" ue="180" us="180"/><bf gi="224" ue="181" us="181"/><bf gi="116" ue="182" us="182"/><bf gi="105" ue="183" us="183"/><bf gi="78" ue="184" us="184"/><bf gi="1204" ue="185" us="185"/><bf gi="67" ue="186" us="186"/><bf gi="96" ue="187" us="187"/><bf gi="1205" ue="190" us="188"/><bf gi="166" ue="191" us="191"/><bf gi="172" ue="197" us="192"/><bf gi="4" ue="198" us="198"/><bf gi="7" ue="199" us="199"/><bf gi="178" ue="207" us="200"/><bf gi="226" ue="208" us="208"/><bf gi="186" ue="214" us="209"/><bf gi="517" ue="215" us="215"/><bf gi="20" ue="216" us="216"/><bf gi="192" ue="220" us="217"/><bf gi="1973" ue="221" us="221"/><bf gi="233" ue="222" us="222"/><bf gi="58" ue="223" us="223"/><bf gi="197" ue="229" us="224"/><bf gi="34" ue="230" us="230"/><bf gi="37" ue="231" us="231"/><bf gi="203" ue="239" us="232"/><bf gi="244" ue="240" us="240"/><bf gi="211" ue="246" us="241"/><bf gi="143" ue="247" us="247"/><bf gi="52" ue="248" us="248"/><bf gi="217" ue="252" us="249"/><bf gi="2312" ue="253" us="253"/><bf gi="285" ue="254" us="254"/><bf gi="221" ue="255" us="255"/><bf gi="1659" ue="256" us="256"/><bf gi="1999" ue="257" us="257"/><bf gi="1660" ue="258" us="258"/><bf gi="2000" ue="259" us="259"/><bf gi="225" ue="260" us="260"/><bf gi="237" ue="261" us="261"/><bf gi="1717" ue="262" us="262"/><bf gi="2033" ue="263" us="263"/><bf gi="1718" ue="264" us="264"/><bf gi="2034" ue="265" us="265"/><bf gi="1720" ue="266" us="266"/><bf gi="2036" ue="267" us="267"/><bf gi="1719" ue="268" us="268"/><bf gi="2035" ue="269" us="269"/><bf gi="1725" ue="270" us="270"/><bf gi="242" ue="271" us="271"/><bf gi="1732" ue="272" us="272"/><bf gi="243" ue="273" us="273"/><bf gi="1735" ue="274" us="274"/><bf gi="2049" ue="275" us="275"/><bf gi="1736" ue="276" us="276"/><bf gi="2050" ue="277" us="277"/><bf gi="1737" ue="278" us="278"/><bf gi="2051" ue="279" us="279"/><bf gi="227" ue="280" us="280"/><bf gi="245" ue="281" us="281"/><bf gi="1734" ue="282" us="282"/><bf gi="2048" ue="283" us="283"/><bf gi="1770" ue="284" us="284"/><bf gi="2092" ue="285" us="285"/><bf gi="1771" ue="286" us="286"/><bf gi="2093" ue="287" us="287"/><bf gi="1772" ue="288" us="288"/><bf gi="2094" ue="289" us="289"/><bf gi="1773" ue="290" us="290"/><bf gi="2095" ue="291" us="291"/><bf gi="1777" ue="292" us="292"/><bf gi="276Line truncated
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Lato-Medium</font-name><full-name>Lato Medium</full-name><family-name>Lato</family-name><embed/><cap-height>717</cap-height><x-height>507</x-height><ascender>805</ascender><descender>-195</descender><bbox><left>-556</left><bottom>-270</bottom><right>1343</right><top>1082</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="1" ue="0" us="0"/><bf gi="171" ue="13" us="13"/><bf gi="2" ue="32" us="32"/><bf gi="82" ue="33" us="33"/><bf gi="122" ue="34" us="34"/><bf gi="134" ue="35" us="35"/><bf gi="130" ue="36" us="36"/><bf gi="166" ue="37" us="37"/><bf gi="123" ue="38" us="38"/><bf gi="121" ue="39" us="39"/><bf gi="108" ue="41" us="40"/><bf gi="114" ue="42" us="42"/><bf gi="144" ue="43" us="43"/><bf gi="84" ue="44" us="44"/><bf gi="102" ue="45" us="45"/><bf gi="87" ue="46" us="46"/><bf gi="99" ue="47" us="47"/><bf gi="135" ue="53" us="48"/><bf gi="164" ue="54" us="54"/><bf gi="141" ue="55" us="55"/><bf gi="165" ue="56" us="56"/><bf gi="142" ue="57" us="57"/><bf gi="86" ue="58" us="58"/><bf gi="85" ue="59" us="59"/><bf gi="149" ue="60" us="60"/><bf gi="146" ue="61" us="61"/><bf gi="150" ue="62" us="62"/><bf gi="83" ue="63" us="63"/><bf gi="124" ue="64" us="64"/><bf gi="3" ue="65" us="65"/><bf gi="5" ue="67" us="66"/><bf gi="8" ue="79" us="68"/><bf gi="22" ue="90" us="80"/><bf gi="110" ue="91" us="91"/><bf gi="101" ue="92" us="92"/><bf gi="111" ue="93" us="93"/><bf gi="119" ue="94" us="94"/><bf gi="105" ue="95" us="95"/><bf gi="68" ue="96" us="96"/><bf gi="33" ue="97" us="97"/><bf gi="35" ue="99" us="98"/><bf gi="38" ue="102" us="100"/><bf gi="43" ue="105" us="103"/><bf gi="47" ue="107" us="106"/><bf gi="163" ue="108" us="108"/><bf gi="49" ue="111" us="109"/><bf gi="54" ue="115" us="112"/><bf gi="59" ue="122" us="116"/><bf gi="112" ue="123" us="123"/><bf gi="100" ue="124" us="124"/><bf gi="113" ue="125" us="125"/><bf gi="120" ue="126" us="126"/><bf gi="2" ue="160" us="160"/><bf gi="167" ue="161" us="161"/><bf gi="131" ue="163" us="162"/><bf gi="455" ue="164" us="164"/><bf gi="133" ue="165" us="165"/><bf gi="452" ue="166" us="166"/><bf gi="117" ue="167" us="167"/><bf gi="73" ue="168" us="168"/><bf gi="125" ue="169" us="169"/><bf gi="66" ue="170" us="170"/><bf gi="97" ue="171" us="171"/><bf gi="154" ue="172" us="172"/><bf gi="102" ue="173" us="173"/><bf gi="126" ue="174" us="174"/><bf gi="74" ue="175" us="175"/><bf gi="128" ue="176" us="176"/><bf gi="151" ue="177" us="177"/><bf gi="1202" ue="179" us="178"/><bf gi="69" ue="180" us="180"/><bf gi="224" ue="181" us="181"/><bf gi="118" ue="182" us="182"/><bf gi="107" ue="183" us="183"/><bf gi="79" ue="184" us="184"/><bf gi="1204" ue="185" us="185"/><bf gi="67" ue="186" us="186"/><bf gi="98" ue="187" us="187"/><bf gi="1205" ue="190" us="188"/><bf gi="168" ue="191" us="191"/><bf gi="172" ue="197" us="192"/><bf gi="4" ue="198" us="198"/><bf gi="7" ue="199" us="199"/><bf gi="178" ue="207" us="200"/><bf gi="226" ue="208" us="208"/><bf gi="186" ue="214" us="209"/><bf gi="517" ue="215" us="215"/><bf gi="20" ue="216" us="216"/><bf gi="192" ue="220" us="217"/><bf gi="2203" ue="221" us="221"/><bf gi="233" ue="222" us="222"/><bf gi="58" ue="223" us="223"/><bf gi="197" ue="229" us="224"/><bf gi="34" ue="230" us="230"/><bf gi="37" ue="231" us="231"/><bf gi="203" ue="239" us="232"/><bf gi="244" ue="240" us="240"/><bf gi="211" ue="246" us="241"/><bf gi="145" ue="247" us="247"/><bf gi="52" ue="248" us="248"/><bf gi="217" ue="252" us="249"/><bf gi="2538" ue="253" us="253"/><bf gi="285" ue="254" us="254"/><bf gi="221" ue="255" us="255"/><bf gi="1889" ue="256" us="256"/><bf gi="2229" ue="257" us="257"/><bf gi="1890" ue="258" us="258"/><bf gi="2230" ue="259" us="259"/><bf gi="225" ue="260" us="260"/><bf gi="237" ue="261" us="261"/><bf gi="1947" ue="262" us="262"/><bf gi="2263" ue="263" us="263"/><bf gi="1948" ue="264" us="264"/><bf gi="2264" ue="265" us="265"/><bf gi="1950" ue="266" us="266"/><bf gi="2266" ue="267" us="267"/><bf gi="1949" ue="268" us="268"/><bf gi="2265" ue="269" us="269"/><bf gi="1955" ue="270" us="270"/><bf gi="242" ue="271" us="271"/><bf gi="1962" ue="272" us="272"/><bf gi="243" ue="273" us="273"/><bf gi="1965" ue="274" us="274"/><bf gi="2279" ue="275" us="275"/><bf gi="1966" ue="276" us="276"/><bf gi="2280" ue="277" us="277"/><bf gi="1967" ue="278" us="278"/><bf gi="2281" ue="279" us="279"/><bf gi="227" ue="280" us="280"/><bf gi="245" ue="281" us="281"/><bf gi="1964" ue="282" us="282"/><bf gi="2278" ue="283" us="283"/><bf gi="2000" ue="284" us="284"/><bf gi="2322" ue="285" us="285"/><bf gi="2001" ue="286" us="286"/><bf gi="2323" ue="287" us="287"/><bf gi="2002" ue="288" us="288"/><bf gi="2324" ue="289" us="289"/><bf gi="2003" ue="290" us="290"/><bf gi="2325" ue="291" us="291"/><bf gi="2007" ue="292" us="292"/><bf gi="276" ue="293" uLine truncated
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Lato-MediumItalic</font-name><full-name>Lato Medium Italic</full-name><family-name>Lato</family-name><embed/><cap-height>717</cap-height><x-height>507</x-height><ascender>805</ascender><descender>-195</descender><bbox><left>-504</left><bottom>-269</bottom><right>1291</right><top>1080</top></bbox><flags>97</flags><stemv>0</stemv><italicangle>-7</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="1" ue="0" us="0"/><bf gi="169" ue="13" us="13"/><bf gi="2" ue="32" us="32"/><bf gi="81" ue="33" us="33"/><bf gi="120" ue="34" us="34"/><bf gi="132" ue="35" us="35"/><bf gi="128" ue="36" us="36"/><bf gi="164" ue="37" us="37"/><bf gi="121" ue="38" us="38"/><bf gi="119" ue="39" us="39"/><bf gi="106" ue="41" us="40"/><bf gi="112" ue="42" us="42"/><bf gi="142" ue="43" us="43"/><bf gi="83" ue="44" us="44"/><bf gi="100" ue="45" us="45"/><bf gi="85" ue="46" us="46"/><bf gi="97" ue="47" us="47"/><bf gi="133" ue="53" us="48"/><bf gi="162" ue="54" us="54"/><bf gi="139" ue="55" us="55"/><bf gi="163" ue="56" us="56"/><bf gi="140" ue="57" us="57"/><bf gi="170" ue="58" us="58"/><bf gi="84" ue="59" us="59"/><bf gi="147" ue="60" us="60"/><bf gi="144" ue="61" us="61"/><bf gi="148" ue="62" us="62"/><bf gi="82" ue="63" us="63"/><bf gi="122" ue="64" us="64"/><bf gi="3" ue="65" us="65"/><bf gi="5" ue="67" us="66"/><bf gi="8" ue="79" us="68"/><bf gi="22" ue="90" us="80"/><bf gi="108" ue="91" us="91"/><bf gi="99" ue="92" us="92"/><bf gi="109" ue="93" us="93"/><bf gi="117" ue="94" us="94"/><bf gi="103" ue="95" us="95"/><bf gi="68" ue="96" us="96"/><bf gi="33" ue="97" us="97"/><bf gi="35" ue="99" us="98"/><bf gi="38" ue="102" us="100"/><bf gi="43" ue="105" us="103"/><bf gi="47" ue="107" us="106"/><bf gi="161" ue="108" us="108"/><bf gi="49" ue="111" us="109"/><bf gi="54" ue="115" us="112"/><bf gi="59" ue="122" us="116"/><bf gi="110" ue="123" us="123"/><bf gi="98" ue="124" us="124"/><bf gi="111" ue="125" us="125"/><bf gi="118" ue="126" us="126"/><bf gi="2" ue="160" us="160"/><bf gi="165" ue="161" us="161"/><bf gi="129" ue="163" us="162"/><bf gi="455" ue="164" us="164"/><bf gi="131" ue="165" us="165"/><bf gi="452" ue="166" us="166"/><bf gi="115" ue="167" us="167"/><bf gi="171" ue="168" us="168"/><bf gi="123" ue="169" us="169"/><bf gi="66" ue="170" us="170"/><bf gi="95" ue="171" us="171"/><bf gi="152" ue="172" us="172"/><bf gi="100" ue="173" us="173"/><bf gi="124" ue="174" us="174"/><bf gi="73" ue="175" us="175"/><bf gi="126" ue="176" us="176"/><bf gi="149" ue="177" us="177"/><bf gi="1202" ue="179" us="178"/><bf gi="69" ue="180" us="180"/><bf gi="224" ue="181" us="181"/><bf gi="116" ue="182" us="182"/><bf gi="105" ue="183" us="183"/><bf gi="78" ue="184" us="184"/><bf gi="1204" ue="185" us="185"/><bf gi="67" ue="186" us="186"/><bf gi="96" ue="187" us="187"/><bf gi="1205" ue="190" us="188"/><bf gi="166" ue="191" us="191"/><bf gi="172" ue="197" us="192"/><bf gi="4" ue="198" us="198"/><bf gi="7" ue="199" us="199"/><bf gi="178" ue="207" us="200"/><bf gi="226" ue="208" us="208"/><bf gi="186" ue="214" us="209"/><bf gi="517" ue="215" us="215"/><bf gi="20" ue="216" us="216"/><bf gi="192" ue="220" us="217"/><bf gi="1973" ue="221" us="221"/><bf gi="233" ue="222" us="222"/><bf gi="58" ue="223" us="223"/><bf gi="197" ue="229" us="224"/><bf gi="34" ue="230" us="230"/><bf gi="37" ue="231" us="231"/><bf gi="203" ue="239" us="232"/><bf gi="244" ue="240" us="240"/><bf gi="211" ue="246" us="241"/><bf gi="143" ue="247" us="247"/><bf gi="52" ue="248" us="248"/><bf gi="217" ue="252" us="249"/><bf gi="2312" ue="253" us="253"/><bf gi="285" ue="254" us="254"/><bf gi="221" ue="255" us="255"/><bf gi="1659" ue="256" us="256"/><bf gi="1999" ue="257" us="257"/><bf gi="1660" ue="258" us="258"/><bf gi="2000" ue="259" us="259"/><bf gi="225" ue="260" us="260"/><bf gi="237" ue="261" us="261"/><bf gi="1717" ue="262" us="262"/><bf gi="2033" ue="263" us="263"/><bf gi="1718" ue="264" us="264"/><bf gi="2034" ue="265" us="265"/><bf gi="1720" ue="266" us="266"/><bf gi="2036" ue="267" us="267"/><bf gi="1719" ue="268" us="268"/><bf gi="2035" ue="269" us="269"/><bf gi="1725" ue="270" us="270"/><bf gi="242" ue="271" us="271"/><bf gi="1732" ue="272" us="272"/><bf gi="243" ue="273" us="273"/><bf gi="1735" ue="274" us="274"/><bf gi="2049" ue="275" us="275"/><bf gi="1736" ue="276" us="276"/><bf gi="2050" ue="277" us="277"/><bf gi="1737" ue="278" us="278"/><bf gi="2051" ue="279" us="279"/><bf gi="227" ue="280" us="280"/><bf gi="245" ue="281" us="281"/><bf gi="1734" ue="282" us="282"/><bf gi="2048" ue="283" us="283"/><bf gi="1770" ue="284" us="284"/><bf gi="2092" ue="285" us="285"/><bf gi="1771" ue="286" us="286"/><bf gi="2093" ue="287" us="287"/><bf gi="1772" ue="288" us="288"/><bf gi="2094" ue="289" us="289"/><bf gi="1773" ue="290" us="290"/><bf gi="2095" ue="291" us="291"/><bf gi="1777" ue="292" us="292"/><bf gi="2Line truncated
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><font-metrics metrics-version="2" type="TYPE0"><font-name>Lato-Regular</font-name><full-name>Lato Regular</full-name><family-name>Lato</family-name><embed/><cap-height>716</cap-height><x-height>506</x-height><ascender>805</ascender><descender>-195</descender><bbox><left>-546</left><bottom>-268</bottom><right>1342</right><top>1078</top></bbox><flags>33</flags><stemv>0</stemv><italicangle>0</italicangle><subtype>TYPE0</subtype><multibyte-extras><cid-type>CIDFontType2</cid-type><default-width>0</default-width><bfranges><bf gi="1" ue="0" us="0"/><bf gi="171" ue="13" us="13"/><bf gi="2" ue="32" us="32"/><bf gi="82" ue="33" us="33"/><bf gi="122" ue="34" us="34"/><bf gi="134" ue="35" us="35"/><bf gi="130" ue="36" us="36"/><bf gi="166" ue="37" us="37"/><bf gi="123" ue="38" us="38"/><bf gi="121" ue="39" us="39"/><bf gi="108" ue="41" us="40"/><bf gi="114" ue="42" us="42"/><bf gi="144" ue="43" us="43"/><bf gi="84" ue="44" us="44"/><bf gi="102" ue="45" us="45"/><bf gi="87" ue="46" us="46"/><bf gi="99" ue="47" us="47"/><bf gi="135" ue="53" us="48"/><bf gi="164" ue="54" us="54"/><bf gi="141" ue="55" us="55"/><bf gi="165" ue="56" us="56"/><bf gi="142" ue="57" us="57"/><bf gi="86" ue="58" us="58"/><bf gi="85" ue="59" us="59"/><bf gi="149" ue="60" us="60"/><bf gi="146" ue="61" us="61"/><bf gi="150" ue="62" us="62"/><bf gi="83" ue="63" us="63"/><bf gi="124" ue="64" us="64"/><bf gi="3" ue="65" us="65"/><bf gi="5" ue="67" us="66"/><bf gi="8" ue="79" us="68"/><bf gi="22" ue="90" us="80"/><bf gi="110" ue="91" us="91"/><bf gi="101" ue="92" us="92"/><bf gi="111" ue="93" us="93"/><bf gi="119" ue="94" us="94"/><bf gi="105" ue="95" us="95"/><bf gi="68" ue="96" us="96"/><bf gi="33" ue="97" us="97"/><bf gi="35" ue="99" us="98"/><bf gi="38" ue="102" us="100"/><bf gi="43" ue="105" us="103"/><bf gi="47" ue="107" us="106"/><bf gi="163" ue="108" us="108"/><bf gi="49" ue="111" us="109"/><bf gi="54" ue="115" us="112"/><bf gi="59" ue="122" us="116"/><bf gi="112" ue="123" us="123"/><bf gi="100" ue="124" us="124"/><bf gi="113" ue="125" us="125"/><bf gi="120" ue="126" us="126"/><bf gi="2" ue="160" us="160"/><bf gi="167" ue="161" us="161"/><bf gi="131" ue="163" us="162"/><bf gi="455" ue="164" us="164"/><bf gi="133" ue="165" us="165"/><bf gi="452" ue="166" us="166"/><bf gi="117" ue="167" us="167"/><bf gi="73" ue="168" us="168"/><bf gi="125" ue="169" us="169"/><bf gi="66" ue="170" us="170"/><bf gi="97" ue="171" us="171"/><bf gi="154" ue="172" us="172"/><bf gi="102" ue="173" us="173"/><bf gi="126" ue="174" us="174"/><bf gi="74" ue="175" us="175"/><bf gi="128" ue="176" us="176"/><bf gi="151" ue="177" us="177"/><bf gi="1202" ue="179" us="178"/><bf gi="69" ue="180" us="180"/><bf gi="224" ue="181" us="181"/><bf gi="118" ue="182" us="182"/><bf gi="107" ue="183" us="183"/><bf gi="79" ue="184" us="184"/><bf gi="1204" ue="185" us="185"/><bf gi="67" ue="186" us="186"/><bf gi="98" ue="187" us="187"/><bf gi="1205" ue="190" us="188"/><bf gi="168" ue="191" us="191"/><bf gi="172" ue="197" us="192"/><bf gi="4" ue="198" us="198"/><bf gi="7" ue="199" us="199"/><bf gi="178" ue="207" us="200"/><bf gi="226" ue="208" us="208"/><bf gi="186" ue="214" us="209"/><bf gi="517" ue="215" us="215"/><bf gi="20" ue="216" us="216"/><bf gi="192" ue="220" us="217"/><bf gi="2203" ue="221" us="221"/><bf gi="233" ue="222" us="222"/><bf gi="58" ue="223" us="223"/><bf gi="197" ue="229" us="224"/><bf gi="34" ue="230" us="230"/><bf gi="37" ue="231" us="231"/><bf gi="203" ue="239" us="232"/><bf gi="244" ue="240" us="240"/><bf gi="211" ue="246" us="241"/><bf gi="145" ue="247" us="247"/><bf gi="52" ue="248" us="248"/><bf gi="217" ue="252" us="249"/><bf gi="2538" ue="253" us="253"/><bf gi="285" ue="254" us="254"/><bf gi="221" ue="255" us="255"/><bf gi="1889" ue="256" us="256"/><bf gi="2229" ue="257" us="257"/><bf gi="1890" ue="258" us="258"/><bf gi="2230" ue="259" us="259"/><bf gi="225" ue="260" us="260"/><bf gi="237" ue="261" us="261"/><bf gi="1947" ue="262" us="262"/><bf gi="2263" ue="263" us="263"/><bf gi="1948" ue="264" us="264"/><bf gi="2264" ue="265" us="265"/><bf gi="1950" ue="266" us="266"/><bf gi="2266" ue="267" us="267"/><bf gi="1949" ue="268" us="268"/><bf gi="2265" ue="269" us="269"/><bf gi="1955" ue="270" us="270"/><bf gi="242" ue="271" us="271"/><bf gi="1962" ue="272" us="272"/><bf gi="243" ue="273" us="273"/><bf gi="1965" ue="274" us="274"/><bf gi="2279" ue="275" us="275"/><bf gi="1966" ue="276" us="276"/><bf gi="2280" ue="277" us="277"/><bf gi="1967" ue="278" us="278"/><bf gi="2281" ue="279" us="279"/><bf gi="227" ue="280" us="280"/><bf gi="245" ue="281" us="281"/><bf gi="1964" ue="282" us="282"/><bf gi="2278" ue="283" us="283"/><bf gi="2000" ue="284" us="284"/><bf gi="2322" ue="285" us="285"/><bf gi="2001" ue="286" us="286"/><bf gi="2323" ue="287" us="287"/><bf gi="2002" ue="288" us="288"/><bf gi="2324" ue="289" us="289"/><bf gi="2003" ue="290" us="290"/><bf gi="2325" ue="291" us="291"/><bf gi="2007" ue="292" us="292"/><bf gi="276" ue="293"Line truncated
|
||||
Binary file not shown.
Loaded 100 of 2237 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user