Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build under Android NDK plus other minor changes #58

Closed
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ add_example(find_calendar_items)
add_example(find_messages)
add_example(find_tasks)
add_example(find_unread_messages)
add_example(office365)
add_example(raw_soap_request)
add_example(send_message)
add_example(update_contact)
Expand Down
1 change: 1 addition & 0 deletions examples/find_calendar_items.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
// The FindItem operation with a CalendarView is a pretty quick query. Note
// however that it cannot return all properties, e.g. an calendar item's body.
// We use a subsequent GetItem operation to get all properties.

int main()
{
int res = EXIT_SUCCESS;
Expand Down
110 changes: 110 additions & 0 deletions examples/office365.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@

// Copyright 2016 otris software AG
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <ews/ews.hpp>

#include <cstdlib>
#include <exception>
#include <iostream>
#include <ostream>
#include <string>

// This example shows how to connect to an Office 365 account via EWS and
// retrieve all calendar items in a given month.

using ews::internal::http_request;

int main()
{
int res = EXIT_SUCCESS;
ews::set_up();

try
{
const auto credentials =
ews::basic_credentials("[email protected]", "secret");

// First, we use Autodiscover to get the EWS end-point URL that we use
// to access Office 365. This should always be something like
// `https://outlook.office365.com/EWS/Exchange.asmx`.

ews::autodiscover_hints hints;
hints.autodiscover_url =
"https://outlook.office365.com/autodiscover/autodiscover.xml";
const auto autodiscover_result =
ews::get_exchange_web_services_url<http_request>(
"[email protected]", credentials, hints);
std::cout << "External EWS URL: "
<< autodiscover_result.external_ews_url << std::endl;

// Next we create a new ews::service instance in order to connect to
// this URL. Note that we use HTML basic authentication rather than
// NTLM to authenticate.

auto service =
ews::service(autodiscover_result.external_ews_url, credentials);

// Actually, this is all it takes to connect to Office 365. The rest is
// EWS as with every on-premises Exchange server. Next we retrieve
// some calendar items from the account.

ews::distinguished_folder_id calendar_folder =
ews::standard_folder::calendar;
std::string start_date("2017-03-01T00:00:00-07:00");
std::string end_date("2017-03-31T23:59:59-07:00");

const auto found_items =
service.find_item(ews::calendar_view(start_date, end_date),
calendar_folder, ews::base_shape::id_only);
std::cout << "# calender items found: " << found_items.size()
<< std::endl;

if (!found_items.empty())
{

std::vector<ews::item_id> ids;
ids.reserve(found_items.size());
std::transform(begin(found_items), end(found_items),
std::back_inserter(ids),
[](const ews::calendar_item& calitem) {
return calitem.get_item_id();
});

const auto calendar_items = service.get_calendar_items(
ids, ews::base_shape::all_properties);

for (const auto& cal_item : calendar_items)
{
std::cout << "\n";

std::cout << "Subject: " << cal_item.get_subject() << "\n"
<< "Start: " << cal_item.get_start().to_string()
<< "\n"
<< "End: " << cal_item.get_end().to_string()
<< "\n\n";
}
}
}
catch (std::exception& exc)
{
std::cout << exc.what() << std::endl;
res = EXIT_FAILURE;
}

ews::tear_down();
return res;
}

// vim:et ts=4 sw=4
78 changes: 74 additions & 4 deletions include/ews/ews.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iterator>
#include <memory>
Expand Down Expand Up @@ -63,6 +64,59 @@
#endif
#endif // !NDEBUG

// To work on windows with or without NOMINMAX defined.
// Allows bare min(a,b), max(a,b) to be used with no
// qualifying namespace.
#if !defined(_WIN32) || defined(NOMINMAX)
namespace ews
{
template <class T>
inline const T& min(const T& a, const T& b)
{
return std::min(a, b);
}

template <class T>
inline const T& max(const T& a, const T& b)
{
return std::max(a, b);
}
} // namespace ews
#endif // !_WIN32 || NOMINMAX

// Workarounds for missing functions in Android NDK
#ifdef __ANDROID__
namespace std
{
template <class T>
inline std::string to_string(const T& val)
{
std::ostringstream os;
os << val;
return os.str();
}

inline int stoi(const std::string& str)
{
return atoi(str.c_str());
}

// This is an incomplete implementation, supporting only bases 8, 10, and 16
inline unsigned long stoul(const std::string& str, std::size_t* pos = 0, int base = 10)
{
std::istringstream is(str);
unsigned long ul;
is >> std::setbase(base) >> std::skipws >> ul;
if (pos)
{
*pos = is.gcount();
}
return ul;
}
}
#endif // __ANDROID__


//! Contains all classes, functions, and enumerations of this library
namespace ews
{
Expand Down Expand Up @@ -419,15 +473,15 @@ class xml_parse_error final : public exception
static std::pair<std::string, std::size_t>
shorten(const std::string& str, std::size_t at, std::size_t columns)
{
at = std::min(at, str.length());
at = min(at, str.length());
if (str.length() < columns)
{
return std::make_pair(str, at);
}

const auto start =
std::max(at - (columns / 2), static_cast<std::size_t>(0));
const auto end = std::min(at + (columns / 2), str.length());
max(at - (columns / 2), static_cast<std::size_t>(0));
const auto end = min(at + (columns / 2), str.length());
EWS_ASSERT(start < end);
std::string line;
std::copy(&str[start], &str[end], std::back_inserter(line));
Expand Down Expand Up @@ -4310,6 +4364,8 @@ namespace internal
{
throw curl_error("Could not start libcurl session");
}
// Needed because some EWS servers use self-signed certificates
curl_easy_setopt(handle_, CURLOPT_SSL_VERIFYPEER, false);
}

~curl_ptr() { curl_easy_cleanup(handle_); }
Expand Down Expand Up @@ -4837,6 +4893,7 @@ namespace internal
}
};
}
#if 0 // KAM - curl_easy_setopt does not take 4 args

template <typename T1, typename T2>
void set_option(CURLoption option, T1 arg1, T2 arg2)
Expand All @@ -4860,6 +4917,7 @@ namespace internal
}
};
}
#endif
#endif

// Perform the HTTP request and returns the response. This function
Expand Down Expand Up @@ -14006,7 +14064,9 @@ class basic_service final
#endif

//! \brief Constructs a new service with given credentials to a server
//! specified by \p server_uri
//! specified by \p server_uri.
//!
//! This constructor will always use NTLM authentication.
basic_service(const std::string& server_uri, const std::string& domain,
const std::string& username, const std::string& password)
: request_handler_(server_uri), server_version_("Exchange2013_SP1")
Expand All @@ -14017,6 +14077,16 @@ class basic_service final
request_handler_.set_credentials(creds);
}

//! \brief Constructs a new service with given credentials to a server
//! specified by \p server_uri
basic_service(const std::string& server_uri, const internal::credentials& creds)
: request_handler_(server_uri), server_version_("Exchange2013_SP1")
{
request_handler_.set_method(RequestHandler::method::POST);
request_handler_.set_content_type("text/xml; charset=utf-8");
request_handler_.set_credentials(creds);
}

//! \brief Sets the schema version that will be used in requests made
//! by this service
void set_request_server_version(server_version vers)
Expand Down
10 changes: 9 additions & 1 deletion include/ews/ews_test_support.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,15 @@ namespace test
std::string autodiscover_password;

environment()
: domain(getenv_or_throw("EWS_TEST_DOMAIN")),
: domain(
#if _WIN32
// Windows does not support empty environment variables
// domain may be legitimately empty
getenv_or_empty_string("EWS_TEST_DOMAIN")
#else
getenv_or_throw("EWS_TEST_DOMAIN")
#endif
),
username(getenv_or_throw("EWS_TEST_USERNAME")),
password(getenv_or_throw("EWS_TEST_PASSWORD")),
server_uri(getenv_or_throw("EWS_TEST_URI")),
Expand Down
6 changes: 4 additions & 2 deletions include/ews/rapidxml/rapidxml.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1294,7 +1294,7 @@ namespace rapidxml
//! Constructs an empty attribute with the specified type.
//! Consider using memory_pool of appropriate xml_document if allocating
//! attributes manually.
xml_attribute() {}
xml_attribute() : m_prev_attribute(nullptr), m_next_attribute(nullptr) {}

///////////////////////////////////////////////////////////////////////////
// Related nodes access
Expand Down Expand Up @@ -1445,7 +1445,9 @@ namespace rapidxml
//! manually.
//! \param type Type of node to construct.
explicit xml_node(node_type type)
: m_type(type), m_first_node(0), m_first_attribute(0)
: m_type(type), m_first_node(nullptr), m_last_node(nullptr)
, m_first_attribute(nullptr), m_last_attribute(nullptr)
, m_prev_sibling(nullptr), m_next_sibling(nullptr)
{
}

Expand Down
2 changes: 1 addition & 1 deletion tests/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ void init_from_args(int* argc, char** argv)
"invoke with --gtest_help to see Google Test flags"
<< std::endl;

std::exit(EXIT_FAILURE);
std::exit(EXIT_SUCCESS);
}
else if (is("--gtest_help", arg, args))
{
Expand Down