123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712 |
- /*
- * Copyright 2005 - 2016 Zarafa and its licensors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
- #include "config.h"
- #include <kopano/platform.h>
- #include <memory>
- #include <new>
- #include <type_traits>
- #include <climits>
- #include <poll.h>
- #include "mapidefs.h"
- #include <mapix.h>
- #include <kopano/MAPIErrors.h>
- #include "Http.h"
- #include "CalDavUtil.h"
- #include "iCal.h"
- #include "WebDav.h"
- #include "CalDavProto.h"
- #include "ProtocolBase.h"
- #include <csignal>
- #include <iostream>
- #include <string>
- #include <kopano/ECLogger.h>
- #include <kopano/ECChannel.h>
- #include <kopano/memory.hpp>
- #include <kopano/my_getopt.h>
- #include <kopano/ecversion.h>
- #include <kopano/CommonUtil.h>
- #include "SSLUtil.h"
- #include "TmpPath.h"
- using namespace std;
- #include <execinfo.h>
- #include <kopano/UnixUtil.h>
- #include <unicode/uclean.h>
- #include <openssl/ssl.h>
- struct HandlerArgs {
- ECChannel *lpChannel;
- bool bUseSSL;
- };
- static bool g_bDaemonize = true;
- static bool g_bQuit = false;
- static bool g_bThreads = false;
- static ECLogger *g_lpLogger = NULL;
- static ECConfig *g_lpConfig = NULL;
- static pthread_t mainthread;
- static int nChildren = 0;
- static HRESULT HrSetupListeners(int *lpulNormalSocket, int *lpulSecureSocket);
- static HRESULT HrProcessConnections(int ulNormalSocket, int ulSecureSocket);
- static HRESULT HrStartHandlerClient(ECChannel *lpChannel, bool bUseSSL, int nCloseFDs, int *pCloseFDs);
- static void *HandlerClient(void *lpArg);
- static HRESULT HrHandleRequest(ECChannel *lpChannel);
- #define KEEP_ALIVE_TIME 300
- static void sigterm(int)
- {
- g_bQuit = true;
- }
- static void sighup(int)
- {
- if (g_bThreads && pthread_equal(pthread_self(), mainthread)==0)
- return;
- if (g_lpConfig != nullptr && !g_lpConfig->ReloadSettings() &&
- g_lpLogger != nullptr)
- ec_log_crit("Unable to reload configuration file, continuing with current settings.");
- if (g_lpLogger) {
- if (g_lpConfig) {
- const char *ll = g_lpConfig->GetSetting("log_level");
- int new_ll = ll ? atoi(ll) : EC_LOGLEVEL_WARNING;
- g_lpLogger->SetLoglevel(new_ll);
- }
- g_lpLogger->Reset();
- ec_log_warn("Log connection was reset");
- }
- }
- static void sigchld(int)
- {
- int stat;
- while (waitpid (-1, &stat, WNOHANG) > 0)
- --nChildren;
- }
- static void sigsegv(int signr, siginfo_t *si, void *uc)
- {
- generic_sigsegv_handler(g_lpLogger, "CalDAV",
- PROJECT_VERSION_GATEWAY_STR, signr, si, uc);
- }
- static void PrintHelp(const char *name)
- {
- cout << "Usage:\n" << endl;
- cout << name << " [-h] [-F] [-V] [-c <configfile>]" << endl;
- cout << " -F\t\tDo not run in the background" << endl;
- cout << " -h\t\tShows this help." << endl;
- cout << " -V\t\tPrint version info." << endl;
- cout << " -c filename\tUse alternate config file (e.g. /etc/kopano/ical.cfg)\n\t\tDefault: /etc/kopano/ical.cfg" << endl;
- cout << endl;
- }
- static void PrintVersion(void)
- {
- cout << "Product version:\t" << PROJECT_VERSION_CALDAV_STR << endl << "File version:\t\t" << PROJECT_SVN_REV_STR << endl;
- }
- int main(int argc, char **argv) {
- HRESULT hr = hrSuccess;
- int ulListenCalDAV = 0;
- int ulListenCalDAVs = 0;
- bool bIgnoreUnknownConfigOptions = false;
- stack_t st = {0};
- struct sigaction act;
- // Configuration
- int opt = 0;
- const char *lpszCfg = ECConfig::GetDefaultPath("ical.cfg");
- static const configsetting_t lpDefaults[] = {
- { "run_as_user", "kopano" },
- { "run_as_group", "kopano" },
- { "pid_file", "/var/run/kopano/ical.pid" },
- { "running_path", "/var/lib/kopano" },
- { "process_model", "fork" },
- { "server_bind", "" },
- { "ical_port", "8080" },
- { "ical_enable", "yes" },
- { "icals_port", "8443" },
- { "icals_enable", "no" },
- { "enable_ical_get", "yes", CONFIGSETTING_RELOADABLE },
- { "server_socket", "http://localhost:236/" },
- { "server_timezone","Europe/Amsterdam"},
- { "default_charset","utf-8"},
- { "log_method", "file" },
- { "log_file", "/var/log/kopano/ical.log" },
- { "log_level", "3", CONFIGSETTING_RELOADABLE },
- { "log_timestamp", "1" },
- { "log_buffer_size", "0" },
- { "ssl_private_key_file", "/etc/kopano/ical/privkey.pem" },
- { "ssl_certificate_file", "/etc/kopano/ical/cert.pem" },
- #ifdef SSL_TXT_SSLV2
- { "ssl_protocols", "!SSLv2" },
- #else
- {"ssl_protocols", ""},
- #endif
- { "ssl_ciphers", "ALL:!LOW:!SSLv2:!EXP:!aNULL" },
- { "ssl_prefer_server_ciphers", "no" },
- { "ssl_verify_client", "no" },
- { "ssl_verify_file", "" },
- { "ssl_verify_path", "" },
- { "tmp_path", "/tmp" },
- { NULL, NULL },
- };
- enum {
- OPT_IGNORE_UNKNOWN_CONFIG_OPTIONS = UCHAR_MAX + 1,
- };
- static const struct option long_options[] = {
- {"help", no_argument, NULL, 'h'},
- {"config", required_argument, NULL, 'c'},
- {"version", no_argument, NULL, 'v'},
- {"foreground", no_argument, NULL, 'F'},
- {"ignore-unknown-config-options", 0, NULL, OPT_IGNORE_UNKNOWN_CONFIG_OPTIONS },
- {NULL, 0, NULL, 0}
- };
- setlocale(LC_CTYPE, "");
- while (1) {
- opt = my_getopt_long_permissive(argc, argv, "Fhc:V", long_options, NULL);
- if (opt == -1)
- break;
- switch (opt) {
- case 'c':
- lpszCfg = optarg;
- break;
- case 'F':
- g_bDaemonize = false;
- break;
- case OPT_IGNORE_UNKNOWN_CONFIG_OPTIONS:
- bIgnoreUnknownConfigOptions = true;
- break;
- case 'V':
- PrintVersion();
- goto exit;
- case 'h':
- default:
- PrintHelp(argv[0]);
- goto exit;
- }
- }
-
- // init xml parser
- xmlInitParser();
- g_lpConfig = ECConfig::Create(lpDefaults);
- if (!g_lpConfig->LoadSettings(lpszCfg) ||
- g_lpConfig->ParseParams(argc - optind, &argv[optind]) < 0 ||
- (!bIgnoreUnknownConfigOptions && g_lpConfig->HasErrors())) {
- g_lpLogger = new ECLogger_File(1, 0, "-", false);
- if (g_lpLogger == nullptr) {
- hr = MAPI_E_NOT_ENOUGH_MEMORY;
- goto exit;
- }
- ec_log_set(g_lpLogger);
- LogConfigErrors(g_lpConfig);
- goto exit;
- }
- g_lpLogger = CreateLogger(g_lpConfig, argv[0], "KopanoICal");
- if (!g_lpLogger) {
- fprintf(stderr, "Error loading configuration or parsing commandline arguments.\n");
- goto exit;
- }
- ec_log_set(g_lpLogger);
- if ((bIgnoreUnknownConfigOptions && g_lpConfig->HasErrors()) || g_lpConfig->HasWarnings())
- LogConfigErrors(g_lpConfig);
- if (!TmpPath::getInstance() -> OverridePath(g_lpConfig))
- ec_log_err("Ignoring invalid path-setting!");
- if (strncmp(g_lpConfig->GetSetting("process_model"), "thread", strlen("thread")) == 0)
- g_bThreads = true;
- // initialize SSL threading
- ssl_threading_setup();
- hr = HrSetupListeners(&ulListenCalDAV, &ulListenCalDAVs);
- if (hr != hrSuccess)
- goto exit;
- // setup signals
- signal(SIGTERM, sigterm);
- signal(SIGINT, sigterm);
- signal(SIGHUP, sighup);
- signal(SIGCHLD, sigchld);
- signal(SIGPIPE, SIG_IGN);
- memset(&st, 0, sizeof(st));
- memset(&act, 0, sizeof(act));
- st.ss_sp = malloc(65536);
- st.ss_flags = 0;
- st.ss_size = 65536;
- act.sa_sigaction = sigsegv;
- act.sa_flags = SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
- sigemptyset(&act.sa_mask);
- sigaltstack(&st, NULL);
- sigaction(SIGSEGV, &act, NULL);
- sigaction(SIGBUS, &act, NULL);
- sigaction(SIGABRT, &act, NULL);
- // fork if needed and drop privileges as requested.
- // this must be done before we do anything with pthreads
- if (unix_runas(g_lpConfig))
- goto exit;
- if (g_bDaemonize && unix_daemonize(g_lpConfig))
- goto exit;
- if (!g_bDaemonize)
- setsid();
- unix_create_pidfile(argv[0], g_lpConfig);
- if (g_bThreads == false)
- g_lpLogger = StartLoggerProcess(g_lpConfig, g_lpLogger);
- else
- g_lpLogger->SetLogprefix(LP_TID);
- ec_log_set(g_lpLogger);
- hr = MAPIInitialize(NULL);
- if (hr != hrSuccess) {
- fprintf(stderr, "Messaging API could not be initialized: %s (%x)",
- GetMAPIErrorMessage(hr), hr);
- goto exit;
- }
- if (g_bThreads)
- mainthread = pthread_self();
- ec_log_info("Starting kopano-ical version " PROJECT_VERSION_CALDAV_STR " (" PROJECT_SVN_REV_STR "), pid %d", getpid());
- hr = HrProcessConnections(ulListenCalDAV, ulListenCalDAVs);
- if (hr != hrSuccess)
- goto exit2;
- ec_log_info("CalDAV Gateway will now exit");
- // in forked mode, send all children the exit signal
- if (g_bThreads == false) {
- int i;
- signal(SIGTERM, SIG_IGN);
- kill(0, SIGTERM);
- i = 30; // wait max 30 seconds
- while (nChildren && i) {
- if (i % 5 == 0)
- ec_log_notice("Waiting for %d processes to exit", nChildren);
- sleep(1);
- --i;
- }
- if (nChildren)
- ec_log_notice("Forced shutdown with %d processes left", nChildren);
- else
- ec_log_info("CalDAV Gateway shutdown complete");
- }
- exit2:
- MAPIUninitialize();
- exit:
- free(st.ss_sp);
- ECChannel::HrFreeCtx();
- delete g_lpConfig;
- DeleteLogger(g_lpLogger);
- SSL_library_cleanup(); // Remove SSL data for the main application and other related libraries
- // Cleanup SSL parts
- ssl_threading_cleanup();
- // Cleanup libxml2 library
- xmlCleanupParser();
- // cleanup ICU data so valgrind is happy
- u_cleanup();
- return hr;
- }
- static HRESULT HrSetupListeners(int *lpulNormal, int *lpulSecure)
- {
- HRESULT hr;
- bool bListen;
- bool bListenSecure;
- int ulPortICal;
- int ulPortICalS;
- int ulNormalSocket = 0;
- int ulSecureSocket = 0;
- // setup sockets
- bListenSecure = (strcasecmp(g_lpConfig->GetSetting("icals_enable"), "yes") == 0);
- bListen = (strcasecmp(g_lpConfig->GetSetting("ical_enable"), "yes") == 0);
- if (!bListen && !bListenSecure) {
- ec_log_crit("No ports to open for listening.");
- return MAPI_E_INVALID_PARAMETER;
- }
- ulPortICal = atoi(g_lpConfig->GetSetting("ical_port"));
- ulPortICalS = atoi(g_lpConfig->GetSetting("icals_port"));
- // start listening on normal port
- if (bListen) {
- hr = HrListen(g_lpConfig->GetSetting("server_bind"), ulPortICal, &ulNormalSocket);
- if (hr != hrSuccess) {
- ec_log_crit("Could not listen on port %d. (0x%08X %s)", ulPortICal, hr, GetMAPIErrorMessage(hr));
- bListen = false;
- } else {
- ec_log_info("Listening on port %d.", ulPortICal);
- }
- }
- // start listening on secure port
- if (bListenSecure) {
- hr = ECChannel::HrSetCtx(g_lpConfig);
- if (hr == hrSuccess) {
- hr = HrListen(g_lpConfig->GetSetting("server_bind"), ulPortICalS, &ulSecureSocket);
- if (hr != hrSuccess) {
- ec_log_crit("Could not listen on secure port %d. (0x%08X %s)", ulPortICalS, hr, GetMAPIErrorMessage(hr));
- bListenSecure = false;
- }
- ec_log_info("Listening on secure port %d.", ulPortICalS);
- } else {
- ec_log_crit("Could not listen on secure port %d. (0x%08X %s)", ulPortICalS, hr, GetMAPIErrorMessage(hr));
- bListenSecure = false;
- }
- }
- if (!bListen && !bListenSecure) {
- ec_log_crit("No ports have been opened for listening, exiting.");
- return MAPI_E_INVALID_PARAMETER;
- }
- *lpulNormal = ulNormalSocket;
- *lpulSecure = ulSecureSocket;
- return hrSuccess;
- }
- /**
- * Listen to the passed sockets and calls HrStartHandlerClient for
- * every incoming connection.
- *
- * @param[in] ulNormalSocket Listening socket of incoming HTTP connections
- * @param[in] ulSecureSocket Listening socket of incoming HTTPS connections
- * @retval MAPI error code
- */
- static HRESULT HrProcessConnections(int ulNormalSocket, int ulSecureSocket)
- {
- HRESULT hr = hrSuccess;
- struct pollfd pollfd[2];
- bool bUseSSL;
- ECChannel *lpChannel = NULL;
- int nCloseFDs = 0, pCloseFDs[2] = {0}, pfd_normal = -1, pfd_secure = -1;
- if (ulNormalSocket) {
- pCloseFDs[nCloseFDs] = pollfd[nCloseFDs].fd = ulNormalSocket;
- pfd_normal = nCloseFDs++;
- }
- if (ulSecureSocket) {
- pCloseFDs[nCloseFDs] = pollfd[nCloseFDs].fd = ulSecureSocket;
- pfd_secure = nCloseFDs++;
- }
- for (size_t i = 0; i < nCloseFDs; ++i)
- pollfd[i].events = POLLIN | POLLRDHUP;
- // main program loop
- while (!g_bQuit) {
- for (size_t i = 0; i < nCloseFDs; ++i)
- pollfd[i].revents = 0;
- // Check whether there are incoming connections.
- int err = poll(pollfd, nCloseFDs, 10 * 1000);
- if (err < 0) {
- if (errno != EINTR) {
- ec_log_crit("An unknown socket error has occurred.");
- g_bQuit = true;
- hr = MAPI_E_NETWORK_ERROR;
- }
- continue;
- } else if (err == 0) {
- continue;
- }
- if (g_bQuit) {
- hr = hrSuccess;
- break;
- }
- // Check if a normal connection is waiting.
- if (pfd_normal >= 0 && pollfd[pfd_normal].revents & (POLLIN | POLLRDHUP)) {
- ec_log_info("Connection waiting on port %d.", atoi(g_lpConfig->GetSetting("ical_port")));
- bUseSSL = false;
- hr = HrAccept(ulNormalSocket, &lpChannel);
- if (hr != hrSuccess) {
- ec_log_err("Could not accept incoming connection on port %d. (0x%08X)", atoi(g_lpConfig->GetSetting("ical_port")), hr);
- continue;
- }
- // Check if a secure connection is waiting.
- } else if (pfd_secure >= 0 && pollfd[pfd_secure].revents & (POLLIN | POLLRDHUP)) {
- ec_log_info("Connection waiting on secure port %d.", atoi(g_lpConfig->GetSetting("icals_port")));
- bUseSSL = true;
- hr = HrAccept(ulSecureSocket, &lpChannel);
- if (hr != hrSuccess) {
- ec_log_err("Could not accept incoming secure connection on port %d. (0x%08X %s)", atoi(g_lpConfig->GetSetting("ical_port")), hr, GetMAPIErrorMessage(hr));
- continue;
- }
- } else {
- continue;
- }
- hr = HrStartHandlerClient(lpChannel, bUseSSL, nCloseFDs, pCloseFDs);
- if (hr != hrSuccess) {
- delete lpChannel; // destructor closes sockets
- ec_log_err("Handling client connection failed. (0x%08X %s)", hr, GetMAPIErrorMessage(hr));
- continue;
- }
- if (g_bThreads == false)
- delete lpChannel; // always cleanup channel in main process
- }
- return hr;
- }
- /**
- * Starts a new thread or forks a child to process the incoming
- * connection.
- *
- * @param[in] lpChannel The accepted connection in ECChannel object
- * @param[in] bUseSSL The ECChannel object is an SSL connection
- * @param[in] nCloseFDs Number of FDs in pCloseFDs, used on forks only
- * @param[in] pCloseFDs Array of FDs to close in child process
- * @retval E_FAIL when thread of child did not start
- */
- static HRESULT HrStartHandlerClient(ECChannel *lpChannel, bool bUseSSL,
- int nCloseFDs, int *pCloseFDs)
- {
- HRESULT hr = hrSuccess;
- pthread_attr_t pThreadAttr;
- pthread_t pThread;
- auto lpHandlerArgs = new HandlerArgs;
- lpHandlerArgs->lpChannel = lpChannel;
- lpHandlerArgs->bUseSSL = bUseSSL;
- if (g_bThreads) {
- pthread_attr_init(&pThreadAttr);
- if (pthread_attr_setdetachstate(&pThreadAttr, PTHREAD_CREATE_DETACHED) != 0)
- ec_log_warn("Could not set thread attribute to detached.");
- if (pthread_create(&pThread, &pThreadAttr, HandlerClient, lpHandlerArgs) != 0) {
- ec_log_err("Could not create thread.");
- hr = E_FAIL;
- goto exit;
- }
- set_thread_name(pThread, std::string("ZCalDAV") + lpChannel->peer_addr());
- }
- else {
- if (unix_fork_function(HandlerClient, lpHandlerArgs, nCloseFDs, pCloseFDs) < 0) {
- ec_log_err("Could not create process.");
- hr = E_FAIL;
- goto exit;
- }
- ++nChildren;
- }
- exit:
- if (hr != hrSuccess)
- delete lpHandlerArgs;
- return hr;
- }
- static void *HandlerClient(void *lpArg)
- {
- HRESULT hr = hrSuccess;
- auto lpHandlerArgs = static_cast<HandlerArgs *>(lpArg);
- ECChannel *lpChannel = lpHandlerArgs->lpChannel;
- bool bUseSSL = lpHandlerArgs->bUseSSL;
- delete lpHandlerArgs;
- if (bUseSSL && lpChannel->HrEnableTLS() != hrSuccess) {
- ec_log_err("Unable to negotiate SSL connection");
- goto exit;
- }
- while (!g_bQuit) {
- hr = lpChannel->HrSelect(KEEP_ALIVE_TIME);
- if (hr == MAPI_E_CANCEL)
- /* signalled - reevaluate g_bQuit */
- continue;
- if (hr != hrSuccess) {
- ec_log_info("Request timeout, closing connection");
- break;
- }
- //Save mapi session between Requests
- hr = HrHandleRequest(lpChannel);
- if (hr != hrSuccess)
- break;
- }
- exit:
- ec_log_info("Connection closed");
- delete lpChannel;
- return NULL;
- }
- static HRESULT HrHandleRequest(ECChannel *lpChannel)
- {
- HRESULT hr = hrSuccess;
- std::wstring wstrUser;
- std::wstring wstrPass;
- std::string strUrl;
- std::string strMethod;
- std::string strServerTZ = g_lpConfig->GetSetting("server_timezone");
- std::string strCharset;
- std::string strUserAgent, strUserAgentVersion;
- std::unique_ptr<ProtocolBase> lpBase;
- KCHL::object_ptr<IMAPISession> lpSession;
- Http lpRequest(lpChannel, g_lpConfig);
- ULONG ulFlag = 0;
- ec_log_debug("New Request");
- hr = lpRequest.HrReadHeaders();
- if(hr != hrSuccess) {
- hr = MAPI_E_USER_CANCEL; // connection is closed by client no data to be read
- goto exit;
- }
- hr = lpRequest.HrValidateReq();
- if(hr != hrSuccess) {
- lpRequest.HrResponseHeader(501, "Not Implemented");
- lpRequest.HrResponseBody("\nRequest not implemented");
- goto exit;
- }
- // ignore Empty Body
- lpRequest.HrReadBody();
- // no error, defaults to UTF-8
- lpRequest.HrGetCharSet(&strCharset);
- // ignore Empty User field.
- lpRequest.HrGetUser(&wstrUser);
- // ignore Empty Password field
- lpRequest.HrGetPass(&wstrPass);
- // no checks required as HrValidateReq() checks Method
- lpRequest.HrGetMethod(&strMethod);
- //
- lpRequest.HrSetKeepAlive(KEEP_ALIVE_TIME);
- lpRequest.HrGetUserAgent(&strUserAgent);
- lpRequest.HrGetUserAgentVersion(&strUserAgentVersion);
- hr = lpRequest.HrGetUrl(&strUrl);
- if (hr != hrSuccess) {
- ec_log_debug("URl is empty for method %s", strMethod.c_str());
- lpRequest.HrResponseHeader(400,"Bad Request");
- lpRequest.HrResponseBody("Bad Request");
- goto exit;
- }
- hr = HrParseURL(strUrl, &ulFlag);
- if (hr != hrSuccess) {
- ec_log_err("Client request is invalid: 0x%08X %s", hr, GetMAPIErrorMessage(hr));
- lpRequest.HrResponseHeader(400, "Bad Request: " + stringify(hr,true));
- goto exit;
- }
- if (ulFlag & SERVICE_CALDAV)
- // this header is always present in a caldav response, but not in ical.
- lpRequest.HrResponseHeader("DAV", "1, access-control, calendar-access, calendar-schedule, calendarserver-principal-property-search");
- if(!strMethod.compare("OPTIONS"))
- {
- lpRequest.HrResponseHeader(200, "OK");
- // @todo, if ical get is disabled, do not add GET as allowed option
- // @todo, should check write access on url and only return read actions if not available
- lpRequest.HrResponseHeader("Allow", "OPTIONS, GET, POST, PUT, DELETE, MOVE");
- lpRequest.HrResponseHeader("Allow", "PROPFIND, PROPPATCH, REPORT, MKCALENDAR");
- // most clients do not login with this action, no need to complain.
- hr = hrSuccess;
- goto exit;
- }
-
- if (wstrUser.empty() || wstrPass.empty()) {
- ec_log_info("Sending authentication request");
- hr = MAPI_E_CALL_FAILED;
- } else {
- lpRequest.HrGetMethod(&strMethod);
- hr = HrAuthenticate(strUserAgent, strUserAgentVersion, wstrUser, wstrPass, g_lpConfig->GetSetting("server_socket"), &~lpSession);
- if (hr != hrSuccess)
- ec_log_warn("Login failed (0x%08X %s), resending authentication request", hr, GetMAPIErrorMessage(hr));
- }
- if (hr != hrSuccess) {
- if(ulFlag & SERVICE_ICAL)
- lpRequest.HrRequestAuth("Kopano iCal Gateway");
- else
- lpRequest.HrRequestAuth("Kopano CalDav Gateway");
- hr = hrSuccess; //keep connection open.
- goto exit;
- }
- //GET & ical Requests
- // @todo fix caldav GET request
- static_assert(std::is_polymorphic<ProtocolBase>::value, "ProtocolBase needs to be polymorphic for unique_ptr to work");
- if( !strMethod.compare("GET") || !strMethod.compare("HEAD") || ((ulFlag & SERVICE_ICAL) && strMethod.compare("PROPFIND")) )
- {
- lpBase.reset(new iCal(&lpRequest, lpSession, strServerTZ, strCharset));
- }
- //CALDAV Requests
- else if((ulFlag & SERVICE_CALDAV) || ( !strMethod.compare("PROPFIND") && !(ulFlag & SERVICE_ICAL)))
- {
- lpBase.reset(new CalDAV(&lpRequest, lpSession, strServerTZ, strCharset));
- }
- else
- {
- hr = MAPI_E_CALL_FAILED;
- lpRequest.HrResponseHeader(404, "Request not valid for ical or caldav services");
- goto exit;
- }
- hr = lpBase->HrInitializeClass();
- if (hr != hrSuccess) {
- if (hr != MAPI_E_NOT_ME)
- hr = lpRequest.HrToHTTPCode(hr);
- goto exit;
- }
- hr = lpBase->HrHandleCommand(strMethod);
- exit:
- if(hr != hrSuccess && !strMethod.empty() && hr != MAPI_E_NOT_ME)
- ec_log_err("Error processing %s request, error code 0x%08x %s", strMethod.c_str(), hr, GetMAPIErrorMessage(hr));
- if (hr != MAPI_E_USER_CANCEL) // do not send response to client if connection closed by client.
- hr = lpRequest.HrFinalize();
- ec_log_debug("End Of Request");
- return hr;
- }
|