137d26ae5SAxel Dörfler /*
2f429e4f4SAxel Dörfler * Copyright 2010-2016, Haiku Inc. All Rights Reserved.
337d26ae5SAxel Dörfler * Copyright 2010 Clemens Zeidler. All rights reserved.
437d26ae5SAxel Dörfler *
537d26ae5SAxel Dörfler * Distributed under the terms of the MIT License.
637d26ae5SAxel Dörfler */
737d26ae5SAxel Dörfler
837d26ae5SAxel Dörfler
937d26ae5SAxel Dörfler #include "Protocol.h"
1037d26ae5SAxel Dörfler
1137d26ae5SAxel Dörfler #include "Commands.h"
1237d26ae5SAxel Dörfler
1337d26ae5SAxel Dörfler
1437d26ae5SAxel Dörfler #define DEBUG_IMAP_PROTOCOL
1537d26ae5SAxel Dörfler #ifdef DEBUG_IMAP_PROTOCOL
1637d26ae5SAxel Dörfler # include <stdio.h>
1737d26ae5SAxel Dörfler # define TRACE(...) printf(__VA_ARGS__)
1837d26ae5SAxel Dörfler #else
1937d26ae5SAxel Dörfler # define TRACE(...) ;
2037d26ae5SAxel Dörfler #endif
2137d26ae5SAxel Dörfler
2237d26ae5SAxel Dörfler
2337d26ae5SAxel Dörfler namespace IMAP {
2437d26ae5SAxel Dörfler
2537d26ae5SAxel Dörfler
Protocol()2637d26ae5SAxel Dörfler Protocol::Protocol()
2737d26ae5SAxel Dörfler :
2837d26ae5SAxel Dörfler fSocket(NULL),
2937d26ae5SAxel Dörfler fBufferedSocket(NULL),
307993ddfaSAxel Dörfler fHandlerList(5, false),
3137d26ae5SAxel Dörfler fCommandID(0),
3237d26ae5SAxel Dörfler fIsConnected(false)
3337d26ae5SAxel Dörfler {
3437d26ae5SAxel Dörfler }
3537d26ae5SAxel Dörfler
3637d26ae5SAxel Dörfler
~Protocol()3737d26ae5SAxel Dörfler Protocol::~Protocol()
3837d26ae5SAxel Dörfler {
3937d26ae5SAxel Dörfler delete fSocket;
4037d26ae5SAxel Dörfler delete fBufferedSocket;
4137d26ae5SAxel Dörfler }
4237d26ae5SAxel Dörfler
4337d26ae5SAxel Dörfler
4437d26ae5SAxel Dörfler status_t
Connect(const BNetworkAddress & address,const char * username,const char * password,bool useSSL)4537d26ae5SAxel Dörfler Protocol::Connect(const BNetworkAddress& address, const char* username,
4637d26ae5SAxel Dörfler const char* password, bool useSSL)
4737d26ae5SAxel Dörfler {
4837d26ae5SAxel Dörfler TRACE("Connect\n");
4937d26ae5SAxel Dörfler if (useSSL)
5037d26ae5SAxel Dörfler fSocket = new(std::nothrow) BSecureSocket(address);
5137d26ae5SAxel Dörfler else
5237d26ae5SAxel Dörfler fSocket = new(std::nothrow) BSocket(address);
5337d26ae5SAxel Dörfler
5437d26ae5SAxel Dörfler if (fSocket == NULL)
5537d26ae5SAxel Dörfler return B_NO_MEMORY;
5637d26ae5SAxel Dörfler
5737d26ae5SAxel Dörfler status_t status = fSocket->InitCheck();
5837d26ae5SAxel Dörfler if (status != B_OK)
5937d26ae5SAxel Dörfler return status;
6037d26ae5SAxel Dörfler
6137d26ae5SAxel Dörfler fBufferedSocket = new(std::nothrow) BBufferedDataIO(*fSocket, 32768, false,
6237d26ae5SAxel Dörfler true);
6337d26ae5SAxel Dörfler if (fBufferedSocket == NULL)
6437d26ae5SAxel Dörfler return B_NO_MEMORY;
6537d26ae5SAxel Dörfler
6637d26ae5SAxel Dörfler TRACE("Login\n");
6737d26ae5SAxel Dörfler
6837d26ae5SAxel Dörfler fIsConnected = true;
6937d26ae5SAxel Dörfler
7037d26ae5SAxel Dörfler LoginCommand login(username, password);
7137d26ae5SAxel Dörfler status = ProcessCommand(login);
7237d26ae5SAxel Dörfler if (status != B_OK) {
7337d26ae5SAxel Dörfler _Disconnect();
7437d26ae5SAxel Dörfler return status;
7537d26ae5SAxel Dörfler }
7637d26ae5SAxel Dörfler
7737d26ae5SAxel Dörfler _ParseCapabilities(login.Capabilities());
7817044801SAxel Dörfler
7917044801SAxel Dörfler if (fCapabilities.IsEmpty()) {
8017044801SAxel Dörfler CapabilityHandler capabilityHandler;
8117044801SAxel Dörfler status = ProcessCommand(capabilityHandler);
8217044801SAxel Dörfler if (status != B_OK)
8317044801SAxel Dörfler return status;
8417044801SAxel Dörfler
8517044801SAxel Dörfler _ParseCapabilities(capabilityHandler.Capabilities());
8617044801SAxel Dörfler }
8717044801SAxel Dörfler
883302df14SAxel Dörfler if (Capabilities().Contains("ID")) {
893302df14SAxel Dörfler // Get the server's ID into our log
903302df14SAxel Dörfler class IDCommand : public IMAP::Command, public IMAP::Handler {
913302df14SAxel Dörfler public:
923302df14SAxel Dörfler BString CommandString()
933302df14SAxel Dörfler {
943302df14SAxel Dörfler return "ID NIL";
953302df14SAxel Dörfler }
963302df14SAxel Dörfler
973302df14SAxel Dörfler bool HandleUntagged(IMAP::Response& response)
983302df14SAxel Dörfler {
993302df14SAxel Dörfler if (response.IsCommand("ID") && response.IsListAt(1)) {
1003302df14SAxel Dörfler puts("Server:");
1013302df14SAxel Dörfler ArgumentList& list = response.ListAt(1);
1023302df14SAxel Dörfler for (int32 i = 0; i < list.CountItems(); i += 2) {
1033302df14SAxel Dörfler printf(" %s: %s\n",
1043302df14SAxel Dörfler list.ItemAt(i)->ToString().String(),
1053302df14SAxel Dörfler list.ItemAt(i + 1)->ToString().String());
1063302df14SAxel Dörfler }
1073302df14SAxel Dörfler return true;
1083302df14SAxel Dörfler }
1093302df14SAxel Dörfler
1103302df14SAxel Dörfler return false;
1113302df14SAxel Dörfler }
1123302df14SAxel Dörfler };
1133302df14SAxel Dörfler IDCommand idCommand;
1143302df14SAxel Dörfler ProcessCommand(idCommand);
1153302df14SAxel Dörfler }
11637d26ae5SAxel Dörfler return B_OK;
11737d26ae5SAxel Dörfler }
11837d26ae5SAxel Dörfler
11937d26ae5SAxel Dörfler
12037d26ae5SAxel Dörfler status_t
Disconnect()12137d26ae5SAxel Dörfler Protocol::Disconnect()
12237d26ae5SAxel Dörfler {
12337d26ae5SAxel Dörfler if (IsConnected()) {
12437d26ae5SAxel Dörfler RawCommand command("LOGOUT");
12537d26ae5SAxel Dörfler ProcessCommand(command);
12637d26ae5SAxel Dörfler }
12737d26ae5SAxel Dörfler return _Disconnect();
12837d26ae5SAxel Dörfler }
12937d26ae5SAxel Dörfler
13037d26ae5SAxel Dörfler
13137d26ae5SAxel Dörfler bool
IsConnected()13237d26ae5SAxel Dörfler Protocol::IsConnected()
13337d26ae5SAxel Dörfler {
13437d26ae5SAxel Dörfler return fIsConnected;
13537d26ae5SAxel Dörfler }
13637d26ae5SAxel Dörfler
13737d26ae5SAxel Dörfler
1387993ddfaSAxel Dörfler bool
AddHandler(Handler & handler)1397993ddfaSAxel Dörfler Protocol::AddHandler(Handler& handler)
1407993ddfaSAxel Dörfler {
1417993ddfaSAxel Dörfler return fHandlerList.AddItem(&handler);
1427993ddfaSAxel Dörfler }
1437993ddfaSAxel Dörfler
1447993ddfaSAxel Dörfler
1457993ddfaSAxel Dörfler void
RemoveHandler(Handler & handler)1467993ddfaSAxel Dörfler Protocol::RemoveHandler(Handler& handler)
1477993ddfaSAxel Dörfler {
1487993ddfaSAxel Dörfler fHandlerList.RemoveItem(&handler);
1497993ddfaSAxel Dörfler }
1507993ddfaSAxel Dörfler
1517993ddfaSAxel Dörfler
15237d26ae5SAxel Dörfler status_t
GetFolders(FolderList & folders,BString & separator)153a4bdd26dSAxel Dörfler Protocol::GetFolders(FolderList& folders, BString& separator)
15437d26ae5SAxel Dörfler {
15529871039SAxel Dörfler BStringList allFolders;
15637d26ae5SAxel Dörfler status_t status = _GetAllFolders(allFolders);
15737d26ae5SAxel Dörfler if (status != B_OK)
15837d26ae5SAxel Dörfler return status;
15937d26ae5SAxel Dörfler
16029871039SAxel Dörfler BStringList subscribedFolders;
161a4bdd26dSAxel Dörfler status = GetSubscribedFolders(subscribedFolders, separator);
16237d26ae5SAxel Dörfler if (status != B_OK)
16337d26ae5SAxel Dörfler return status;
16437d26ae5SAxel Dörfler
16529871039SAxel Dörfler for (int32 i = 0; i < allFolders.CountStrings(); i++) {
1669192d4dcSAxel Dörfler FolderEntry entry;
16729871039SAxel Dörfler entry.folder = allFolders.StringAt(i);
16829871039SAxel Dörfler for (int32 j = 0; j < subscribedFolders.CountStrings(); j++) {
169*e378617bSDave Thompson if (entry.folder == subscribedFolders.StringAt(j)) {
1709192d4dcSAxel Dörfler entry.subscribed = true;
17137d26ae5SAxel Dörfler break;
17237d26ae5SAxel Dörfler }
17337d26ae5SAxel Dörfler }
1749192d4dcSAxel Dörfler folders.push_back(entry);
17537d26ae5SAxel Dörfler }
17637d26ae5SAxel Dörfler
17737d26ae5SAxel Dörfler // you could be subscribed to a folder which not exist currently, add them:
17829871039SAxel Dörfler for (int32 i = 0; i < subscribedFolders.CountStrings(); i++) {
17937d26ae5SAxel Dörfler bool isInlist = false;
18029871039SAxel Dörfler for (int32 j = 0; j < allFolders.CountStrings(); j++) {
18129871039SAxel Dörfler if (subscribedFolders.StringAt(i) == allFolders.StringAt(j)) {
18237d26ae5SAxel Dörfler isInlist = true;
18337d26ae5SAxel Dörfler break;
18437d26ae5SAxel Dörfler }
18537d26ae5SAxel Dörfler }
18637d26ae5SAxel Dörfler if (isInlist)
18737d26ae5SAxel Dörfler continue;
18837d26ae5SAxel Dörfler
1899192d4dcSAxel Dörfler FolderEntry entry;
19029871039SAxel Dörfler entry.folder = subscribedFolders.StringAt(i);
1919192d4dcSAxel Dörfler entry.subscribed = true;
1929192d4dcSAxel Dörfler folders.push_back(entry);
19337d26ae5SAxel Dörfler }
19437d26ae5SAxel Dörfler
19537d26ae5SAxel Dörfler return B_OK;
19637d26ae5SAxel Dörfler }
19737d26ae5SAxel Dörfler
19837d26ae5SAxel Dörfler
19937d26ae5SAxel Dörfler status_t
GetSubscribedFolders(BStringList & folders,BString & separator)20029871039SAxel Dörfler Protocol::GetSubscribedFolders(BStringList& folders, BString& separator)
201adbe8fc9SAxel Dörfler {
202adbe8fc9SAxel Dörfler ListCommand command(NULL, true);
203adbe8fc9SAxel Dörfler status_t status = ProcessCommand(command);
204adbe8fc9SAxel Dörfler if (status != B_OK)
205adbe8fc9SAxel Dörfler return status;
206adbe8fc9SAxel Dörfler
207adbe8fc9SAxel Dörfler folders = command.FolderList();
208a4bdd26dSAxel Dörfler separator = command.Separator();
209adbe8fc9SAxel Dörfler return status;
210adbe8fc9SAxel Dörfler }
211adbe8fc9SAxel Dörfler
212adbe8fc9SAxel Dörfler
213adbe8fc9SAxel Dörfler status_t
SubscribeFolder(const char * folder)21437d26ae5SAxel Dörfler Protocol::SubscribeFolder(const char* folder)
21537d26ae5SAxel Dörfler {
21637d26ae5SAxel Dörfler SubscribeCommand command(folder);
21737d26ae5SAxel Dörfler return ProcessCommand(command);
21837d26ae5SAxel Dörfler }
21937d26ae5SAxel Dörfler
22037d26ae5SAxel Dörfler
22137d26ae5SAxel Dörfler status_t
UnsubscribeFolder(const char * folder)22237d26ae5SAxel Dörfler Protocol::UnsubscribeFolder(const char* folder)
22337d26ae5SAxel Dörfler {
22437d26ae5SAxel Dörfler UnsubscribeCommand command(folder);
22537d26ae5SAxel Dörfler return ProcessCommand(command);
22637d26ae5SAxel Dörfler }
22737d26ae5SAxel Dörfler
22837d26ae5SAxel Dörfler
22937d26ae5SAxel Dörfler status_t
GetQuota(uint64 & used,uint64 & total)23037d26ae5SAxel Dörfler Protocol::GetQuota(uint64& used, uint64& total)
23137d26ae5SAxel Dörfler {
23237d26ae5SAxel Dörfler if (!Capabilities().Contains("QUOTA"))
23337d26ae5SAxel Dörfler return B_ERROR;
23437d26ae5SAxel Dörfler
23537d26ae5SAxel Dörfler GetQuotaCommand quotaCommand;
23637d26ae5SAxel Dörfler status_t status = ProcessCommand(quotaCommand);
23737d26ae5SAxel Dörfler if (status != B_OK)
23837d26ae5SAxel Dörfler return status;
23937d26ae5SAxel Dörfler
24037d26ae5SAxel Dörfler used = quotaCommand.UsedStorage();
24137d26ae5SAxel Dörfler total = quotaCommand.TotalStorage();
24237d26ae5SAxel Dörfler return B_OK;
24337d26ae5SAxel Dörfler }
24437d26ae5SAxel Dörfler
24537d26ae5SAxel Dörfler
24637d26ae5SAxel Dörfler status_t
SendCommand(const char * command)24737d26ae5SAxel Dörfler Protocol::SendCommand(const char* command)
24837d26ae5SAxel Dörfler {
24937d26ae5SAxel Dörfler return SendCommand(0, command);
25037d26ae5SAxel Dörfler }
25137d26ae5SAxel Dörfler
25237d26ae5SAxel Dörfler
25337d26ae5SAxel Dörfler status_t
SendCommand(int32 id,const char * command)25437d26ae5SAxel Dörfler Protocol::SendCommand(int32 id, const char* command)
25537d26ae5SAxel Dörfler {
25637d26ae5SAxel Dörfler char buffer[2048];
25737d26ae5SAxel Dörfler int32 length;
258b9962ceaSJérôme Duval if (id > 0) {
259b9962ceaSJérôme Duval length = snprintf(buffer, sizeof(buffer), "A%.7" B_PRId32 " %s\r\n",
260b9962ceaSJérôme Duval id, command);
261b9962ceaSJérôme Duval } else
26237d26ae5SAxel Dörfler length = snprintf(buffer, sizeof(buffer), "%s\r\n", command);
26337d26ae5SAxel Dörfler
264db0a4f2cSAxel Dörfler TRACE("C: %s", buffer);
265db0a4f2cSAxel Dörfler
26637d26ae5SAxel Dörfler ssize_t bytesWritten = fSocket->Write(buffer, length);
26737d26ae5SAxel Dörfler if (bytesWritten < 0)
26837d26ae5SAxel Dörfler return bytesWritten;
26937d26ae5SAxel Dörfler
27037d26ae5SAxel Dörfler return bytesWritten == length ? B_OK : B_ERROR;
27137d26ae5SAxel Dörfler }
27237d26ae5SAxel Dörfler
27337d26ae5SAxel Dörfler
274b9962ceaSJérôme Duval ssize_t
SendData(const char * buffer,uint32 length)27537d26ae5SAxel Dörfler Protocol::SendData(const char* buffer, uint32 length)
27637d26ae5SAxel Dörfler {
27737d26ae5SAxel Dörfler return fSocket->Write(buffer, length);
27837d26ae5SAxel Dörfler }
27937d26ae5SAxel Dörfler
28037d26ae5SAxel Dörfler
28137d26ae5SAxel Dörfler status_t
ProcessCommand(Command & command,bigtime_t timeout)28237d26ae5SAxel Dörfler Protocol::ProcessCommand(Command& command, bigtime_t timeout)
28337d26ae5SAxel Dörfler {
2847993ddfaSAxel Dörfler BString commandString = command.CommandString();
2857993ddfaSAxel Dörfler if (commandString.IsEmpty())
2867993ddfaSAxel Dörfler return B_BAD_VALUE;
28737d26ae5SAxel Dörfler
2887993ddfaSAxel Dörfler Handler* handler = dynamic_cast<Handler*>(&command);
2897993ddfaSAxel Dörfler if (handler != NULL && !AddHandler(*handler))
2907993ddfaSAxel Dörfler return B_NO_MEMORY;
2917993ddfaSAxel Dörfler
2927993ddfaSAxel Dörfler int32 commandID = NextCommandID();
2937993ddfaSAxel Dörfler status_t status = SendCommand(commandID, commandString.String());
2947993ddfaSAxel Dörfler if (status == B_OK) {
2957993ddfaSAxel Dörfler fOngoingCommands[commandID] = &command;
2967993ddfaSAxel Dörfler status = HandleResponse(&command, timeout);
2977993ddfaSAxel Dörfler }
2987993ddfaSAxel Dörfler
2997993ddfaSAxel Dörfler if (handler != NULL)
3007993ddfaSAxel Dörfler RemoveHandler(*handler);
30137d26ae5SAxel Dörfler
30237d26ae5SAxel Dörfler return status;
30337d26ae5SAxel Dörfler }
30437d26ae5SAxel Dörfler
30537d26ae5SAxel Dörfler
3067993ddfaSAxel Dörfler // #pragma mark - protected
3077993ddfaSAxel Dörfler
3087993ddfaSAxel Dörfler
30937d26ae5SAxel Dörfler status_t
HandleResponse(Command * command,bigtime_t timeout,bool disconnectOnTimeout)310077338a9SAxel Dörfler Protocol::HandleResponse(Command* command, bigtime_t timeout,
311077338a9SAxel Dörfler bool disconnectOnTimeout)
31237d26ae5SAxel Dörfler {
31337d26ae5SAxel Dörfler status_t commandStatus = B_OK;
314a5170470SAxel Dörfler IMAP::ResponseParser parser(*fBufferedSocket);
315077338a9SAxel Dörfler if (IMAP::LiteralHandler* literalHandler
316077338a9SAxel Dörfler = dynamic_cast<IMAP::LiteralHandler*>(command))
317077338a9SAxel Dörfler parser.SetLiteralHandler(literalHandler);
318077338a9SAxel Dörfler
31937d26ae5SAxel Dörfler IMAP::Response response;
32037d26ae5SAxel Dörfler
32137d26ae5SAxel Dörfler bool done = false;
32237d26ae5SAxel Dörfler while (!done) {
32337d26ae5SAxel Dörfler try {
32437d26ae5SAxel Dörfler status_t status = parser.NextResponse(response, timeout);
32537d26ae5SAxel Dörfler if (status != B_OK) {
32637d26ae5SAxel Dörfler // we might have lost the connection, clear the connection state
32737d26ae5SAxel Dörfler if (status != B_TIMED_OUT || disconnectOnTimeout)
32837d26ae5SAxel Dörfler _Disconnect();
32937d26ae5SAxel Dörfler
33037d26ae5SAxel Dörfler return status;
33137d26ae5SAxel Dörfler }
33237d26ae5SAxel Dörfler
33337d26ae5SAxel Dörfler if (response.IsUntagged() || response.IsContinuation()) {
33437d26ae5SAxel Dörfler bool handled = false;
3357993ddfaSAxel Dörfler for (int32 i = fHandlerList.CountItems(); i-- > 0;) {
33637d26ae5SAxel Dörfler if (fHandlerList.ItemAt(i)->HandleUntagged(response)) {
33737d26ae5SAxel Dörfler handled = true;
33837d26ae5SAxel Dörfler break;
33937d26ae5SAxel Dörfler }
34037d26ae5SAxel Dörfler }
34137d26ae5SAxel Dörfler if (!handled)
34237d26ae5SAxel Dörfler printf("Unhandled S: %s\n", response.ToString().String());
34337d26ae5SAxel Dörfler } else {
34437d26ae5SAxel Dörfler CommandIDMap::iterator found
34537d26ae5SAxel Dörfler = fOngoingCommands.find(response.Tag());
34637d26ae5SAxel Dörfler if (found != fOngoingCommands.end()) {
34737d26ae5SAxel Dörfler status_t status = found->second->HandleTagged(response);
34837d26ae5SAxel Dörfler if (status != B_OK)
34937d26ae5SAxel Dörfler commandStatus = status;
35037d26ae5SAxel Dörfler
35137d26ae5SAxel Dörfler fOngoingCommands.erase(found);
35237d26ae5SAxel Dörfler } else
35337d26ae5SAxel Dörfler printf("Unknown tag S: %s\n", response.ToString().String());
35437d26ae5SAxel Dörfler }
355a5170470SAxel Dörfler } catch (ParseException& exception) {
35637d26ae5SAxel Dörfler printf("Error during parsing: %s\n", exception.Message());
357f429e4f4SAxel Dörfler } catch (StreamException& exception) {
358f429e4f4SAxel Dörfler return exception.Status();
35937d26ae5SAxel Dörfler }
36037d26ae5SAxel Dörfler
36137d26ae5SAxel Dörfler if (fOngoingCommands.size() == 0)
36237d26ae5SAxel Dörfler done = true;
36337d26ae5SAxel Dörfler }
36437d26ae5SAxel Dörfler
36537d26ae5SAxel Dörfler return commandStatus;
36637d26ae5SAxel Dörfler }
36737d26ae5SAxel Dörfler
36837d26ae5SAxel Dörfler
36937d26ae5SAxel Dörfler int32
NextCommandID()37037d26ae5SAxel Dörfler Protocol::NextCommandID()
37137d26ae5SAxel Dörfler {
37237d26ae5SAxel Dörfler fCommandID++;
37337d26ae5SAxel Dörfler return fCommandID;
37437d26ae5SAxel Dörfler }
37537d26ae5SAxel Dörfler
37637d26ae5SAxel Dörfler
3777993ddfaSAxel Dörfler // #pragma mark - private
37837d26ae5SAxel Dörfler
37937d26ae5SAxel Dörfler
38037d26ae5SAxel Dörfler status_t
_Disconnect()38137d26ae5SAxel Dörfler Protocol::_Disconnect()
38237d26ae5SAxel Dörfler {
38337d26ae5SAxel Dörfler fOngoingCommands.clear();
38437d26ae5SAxel Dörfler fIsConnected = false;
3859192d4dcSAxel Dörfler delete fBufferedSocket;
3869192d4dcSAxel Dörfler fBufferedSocket = NULL;
38737d26ae5SAxel Dörfler delete fSocket;
38837d26ae5SAxel Dörfler fSocket = NULL;
3899192d4dcSAxel Dörfler
39037d26ae5SAxel Dörfler return B_OK;
39137d26ae5SAxel Dörfler }
39237d26ae5SAxel Dörfler
39337d26ae5SAxel Dörfler
39437d26ae5SAxel Dörfler status_t
_GetAllFolders(BStringList & folders)39529871039SAxel Dörfler Protocol::_GetAllFolders(BStringList& folders)
39637d26ae5SAxel Dörfler {
3979192d4dcSAxel Dörfler ListCommand command(NULL, false);
3989192d4dcSAxel Dörfler status_t status = ProcessCommand(command);
39937d26ae5SAxel Dörfler if (status != B_OK)
40037d26ae5SAxel Dörfler return status;
40137d26ae5SAxel Dörfler
4029192d4dcSAxel Dörfler folders = command.FolderList();
40337d26ae5SAxel Dörfler return status;
40437d26ae5SAxel Dörfler }
40537d26ae5SAxel Dörfler
40637d26ae5SAxel Dörfler
40737d26ae5SAxel Dörfler void
_ParseCapabilities(const ArgumentList & arguments)40837d26ae5SAxel Dörfler Protocol::_ParseCapabilities(const ArgumentList& arguments)
40937d26ae5SAxel Dörfler {
41037d26ae5SAxel Dörfler fCapabilities.MakeEmpty();
41137d26ae5SAxel Dörfler
41237d26ae5SAxel Dörfler for (int32 i = 0; i < arguments.CountItems(); i++) {
41337d26ae5SAxel Dörfler if (StringArgument* argument
41437d26ae5SAxel Dörfler = dynamic_cast<StringArgument*>(arguments.ItemAt(i)))
41537d26ae5SAxel Dörfler fCapabilities.AddItem(new StringArgument(*argument));
41637d26ae5SAxel Dörfler }
41737d26ae5SAxel Dörfler
41837d26ae5SAxel Dörfler TRACE("capabilities: %s\n", fCapabilities.ToString().String());
41937d26ae5SAxel Dörfler }
42037d26ae5SAxel Dörfler
42137d26ae5SAxel Dörfler
42237d26ae5SAxel Dörfler } // namespace IMAP
423