blob: 7751fe50785641b97931a6b40fc1899bd74e6aa6 [file] [log] [blame]
atraczykc25f69d2016-11-22 19:55:16 -05001/**************************************************************************
2* Copyright (C) 2016 by Savoir-faire Linux *
3* Author: Jäger Nicolas <nicolas.jager@savoirfairelinux.com> *
4* Author: Traczyk Andreas <traczyk.andreas@savoirfairelinux.com> *
5* *
6* This program is free software; you can redistribute it and/or modify *
7* it under the terms of the GNU General Public License as published by *
8* the Free Software Foundation; either version 3 of the License, or *
9* (at your option) any later version. *
10* *
11* This program is distributed in the hope that it will be useful, *
12* but WITHOUT ANY WARRANTY; without even the implied warranty of *
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14* GNU General Public License for more details. *
15* *
16* You should have received a copy of the GNU General Public License *
17* along with this program. If not, see <http://www.gnu.org/licenses/>. *
18**************************************************************************/
19#include <pch.h>
20
21#include "base64.h"
22
23#include <direct.h>
24
25using namespace RingClientUWP;
26using namespace VCardUtils;
27
28using namespace Windows::UI::Core;
29
30std::string
31getBetweenTokens( const std::string& str,
32 const char* token1,
33 const char* token2 = nullptr)
34{
35 std::size_t start = token1 ? (str.find(token1) + strlen(token1)) : 0;
36 std::size_t length = token2 ? (str.find(token2) - 1 - start) : std::string::npos;
37 return str.substr(start, length);
38}
39
40VCard::VCard(Contact^ owner) : m_Owner(owner)
41{}
42
43int
44VCard::receiveChunk(const std::string& args, const std::string& payload)
45{
46 MSG_("receive VCARD chunk");
47
48 int32_t _id = stoi( getBetweenTokens(args, Symbols::ID_TOKEN, Symbols::PART_TOKEN) );
49 uint32_t _part = stoi( getBetweenTokens(args, Symbols::PART_TOKEN, Symbols::OF_TOKEN) );
50 uint32_t _of = stoi( getBetweenTokens(args, Symbols::OF_TOKEN) );
51
52 std::stringstream _payload(payload);
53 std::string _line;
54
55 if (_part == 1) {
56
57 m_mParts.clear();
58
59 while (std::getline(_payload, _line)) {
60 if (_line.find("UID:") != std::string::npos)
61 break;
62 }
63 m_mParts[Property::UID] = _line.substr(4);
64
atraczyk4ed42ea2016-11-29 11:15:34 -050065 bool fnFound = false;
atraczykc25f69d2016-11-22 19:55:16 -050066 while (std::getline(_payload, _line)) {
atraczyk4ed42ea2016-11-29 11:15:34 -050067 if (_line.find("FN:") != std::string::npos) {
68 fnFound = true;
atraczyka57d7172016-11-29 09:58:35 -050069 break;
atraczyk4ed42ea2016-11-29 11:15:34 -050070 }
atraczyka57d7172016-11-29 09:58:35 -050071 }
atraczyk4ed42ea2016-11-29 11:15:34 -050072 if (fnFound)
73 m_mParts[Property::FN] = _line.substr(3);
atraczyka57d7172016-11-29 09:58:35 -050074
75 while (std::getline(_payload, _line)) {
atraczykc25f69d2016-11-22 19:55:16 -050076 if (_line.find("PHOTO;") != std::string::npos)
77 break;
78 }
atraczyk4ed42ea2016-11-29 11:15:34 -050079
atraczykc25f69d2016-11-22 19:55:16 -050080 // because android client builds vcard differently (TYPE=PNG: vs PNG:)
atraczyk4ed42ea2016-11-29 11:15:34 -050081 size_t pos = _line.find("PNG:");
atraczykaeb4a5c2016-12-01 19:17:18 -050082 if (pos == std::string::npos) {
83 pos = _line.find("JPEG:");
84 if (pos != std::string::npos)
85 m_mParts[Property::PHOTO].append(_line.substr(pos + 5));
86 }
87 else
atraczyk4ed42ea2016-11-29 11:15:34 -050088 m_mParts[Property::PHOTO].append(_line.substr(pos + 4));
89
atraczykc25f69d2016-11-22 19:55:16 -050090 return VCARD_INCOMPLETE;
91 }
92 else {
93 if (_part == _of) {
94 std::getline(_payload, _line);
95 m_mParts[Property::PHOTO].append(_line);
atraczyk4ed42ea2016-11-29 11:15:34 -050096
97 bool fnFound = false;
98 while (std::getline(_payload, _line)) {
99 if (_line.find("FN:") != std::string::npos) {
100 fnFound = true;
101 break;
102 }
103 }
104 if (fnFound)
105 m_mParts[Property::FN] = _line.substr(3);
106
atraczykc25f69d2016-11-22 19:55:16 -0500107 saveToFile();
108 decodeBase64ToPNGFile();
atraczyka57d7172016-11-29 09:58:35 -0500109 if (!m_mParts[Property::FN].empty())
110 m_Owner->_displayName = Utils::toPlatformString(m_mParts[Property::FN]);
111 m_Owner->_vcardUID = Utils::toPlatformString(m_mParts[Property::UID]);
112 ViewModel::ContactsViewModel::instance->saveContactsToFile();
atraczykc25f69d2016-11-22 19:55:16 -0500113 MSG_("VCARD_COMPLETE");
114 return VCARD_COMPLETE;
115 }
116 else {
117 m_mParts[Property::PHOTO].append(payload);
118 return VCARD_INCOMPLETE;
119 }
120 }
121 return VCARD_CHUNK_ERROR;
122}
123
124void
125VCard::send(std::string callID, const char* vCardFile)
126{
127 int i = 0;
atraczyk4ed42ea2016-11-29 11:15:34 -0500128 const int chunkSize = 1024;
atraczykc25f69d2016-11-22 19:55:16 -0500129 std::string vCard;
130 if (vCardFile) {
131 std::ifstream file(vCardFile);
132 vCard.assign(( std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
133 }
134 else
135 vCard = asString();
136 int total = vCard.size() / chunkSize + (vCard.size() % chunkSize ? 1 : 0);
atraczyka57d7172016-11-29 09:58:35 -0500137 std::string idkey = Utils::genID(0LL, 99999999LL);
atraczykc25f69d2016-11-22 19:55:16 -0500138 while ( vCard.size() ) {
139 std::map<std::string, std::string> chunk;
140 std::stringstream key;
141 key << PROFILE_VCF
142 << ";id=" << idkey
143 << ",part=" << std::to_string(i + 1)
144 << ",of=" << std::to_string(total);
145 chunk[key.str()] = vCard.substr(0, chunkSize);
146 vCard = vCard.erase(0, chunkSize);
147 ++i;
148 sendChunk(callID, chunk);
149 }
150}
151
152void
153VCard::sendChunk(std::string callID, std::map<std::string, std::string> chunk)
154{
155 MSG_("sending chunk...");
156 for(auto i : chunk)
157 MSG_("key:" + i.first + "\nvalue:" + i.second);
158 RingD::instance->sendSIPTextMessageVCF(callID, chunk);
159}
160
161std::string
162VCard::asString()
163{
164 std::stringstream ret;
165
166 ret << Symbols::BEGIN_TOKEN << Symbols::END_LINE_TOKEN;
167
168 ret << Property::VERSION << Symbols::SEPERATOR2 << "3.0"
169 << Symbols::END_LINE_TOKEN;
170
171 ret << Property::UID << Symbols::SEPERATOR2 << m_mParts[Property::UID]
172 << Symbols::END_LINE_TOKEN;
173
atraczyka57d7172016-11-29 09:58:35 -0500174 ret << Property::FN << Symbols::SEPERATOR2 << m_mParts[Property::FN]
atraczykc25f69d2016-11-22 19:55:16 -0500175 << Symbols::END_LINE_TOKEN;
176
177 ret << Property::PHOTO << Symbols::SEPERATOR1 << Symbols::PHOTO_ENC
178 << Symbols::SEPERATOR1 << Symbols::PHOTO_TYPE << Symbols::SEPERATOR2
179 << m_mParts[Property::PHOTO] << Symbols::END_LINE_TOKEN;
180
181 ret << Symbols::END_TOKEN;
182
183 return std::string(ret.str());
184}
185
186void
187VCard::decodeBase64ToPNGFile()
188{
189 size_t padding = m_mParts[Property::PHOTO].size() % 4;
190 if (padding)
191 m_mParts[Property::PHOTO].append(padding, 0);
192
193 std::vector<uint8_t> decodedData = ring::base64::decode(m_mParts[Property::PHOTO]);
194 std::string vcardDir(RingD::instance->getLocalFolder() + ".vcards\\");
195 std::string pngFile(m_mParts[Property::UID] + ".png");
196 MSG_("Saving PNG (" + m_mParts[Property::UID] + ") to " + pngFile + "...");
197 if (_mkdir(vcardDir.c_str())) {
198 std::ofstream file(vcardDir + pngFile, std::ios::out | std::ios::trunc | std::ios::binary);
199 if (file.is_open()) {
200 for (auto i : decodedData)
201 file << i;
202 file.close();
atraczyka57d7172016-11-29 09:58:35 -0500203 m_Owner->_avatarImage = Utils::toPlatformString(vcardDir + pngFile);
204 MSG_("Done decoding and saving VCard Photo to PNG");
atraczykc25f69d2016-11-22 19:55:16 -0500205 }
206 }
207}
208
209void
210VCard::encodePNGToBase64()
211{
212 std::string vcardDir(RingD::instance->getLocalFolder() + ".vcards\\");
213 std::string pngFile(m_mParts[Property::UID] + ".png");
214 std::basic_ifstream<uint8_t> file(vcardDir + pngFile, std::ios::in | std::ios::binary);
215 if (file.is_open()) {
216 auto eos = std::istreambuf_iterator<uint8_t>();
217 auto data = std::vector<uint8_t>(std::istreambuf_iterator<uint8_t>(file), eos);
218 m_mParts[Property::PHOTO] = ring::base64::encode(data);
219 file.close();
220 MSG_("Done encoding PNG to b64");
221 }
222}
223
224int
225VCard::saveToFile()
226{
227 std::string vcardDir(RingD::instance->getLocalFolder() + ".vcards\\");
228 std::string vcardFile(m_mParts[Property::UID] + ".vcard");
229 MSG_("Saving VCard (" + m_mParts[Property::UID] + ") to " + vcardFile + "...");
230 if (_mkdir(vcardDir.c_str())) {
231 std::ofstream file(vcardDir + vcardFile, std::ios::out | std::ios::trunc);
232 if (file.is_open()) {
233 file << asString();
234 file.close();
235 MSG_("Done Saving VCard");
236 return 1;
237 }
238 }
239 return 0;
240}
241
242void
243VCard::setData(std::map<std::string, std::string> data)
244{
245 m_mParts = data;
246}