A Fast Bresenham Type Algorithm For Drawing Ellipses by John Kennedy
[xy_vsfilter.git] / src / apps / mplayerc / WebClientSocket.cpp
blob956b494674ba8853edc29909711d983cc88d29b5
1 #include "stdafx.h"
2 #include <atlisapi.h>
3 #include "mplayerc.h"
4 #include "resource.h"
5 #include "MainFrm.h"
6 #include "..\..\subtitles\TextFile.h"
7 #include ".\webserver.h"
8 #include ".\webclientsocket.h"
10 CWebClientSocket::CWebClientSocket(CWebServer* pWebServer, CMainFrame* pMainFrame)
11 : m_pWebServer(pWebServer)
12 , m_pMainFrame(pMainFrame)
16 CWebClientSocket::~CWebClientSocket()
20 bool CWebClientSocket::SetCookie(CString name, CString value, __time64_t expire, CString path, CString domain)
22 if(name.IsEmpty()) return(false);
23 if(value.IsEmpty()) {m_cookie.RemoveKey(name); return true;}
25 m_cookie[name] = value;
27 m_cookieattribs[name].path = path;
28 m_cookieattribs[name].domain = domain;
30 if(expire >= 0)
32 CTime t(expire);
33 SYSTEMTIME st;
34 t.GetAsSystemTime(st);
35 CStringA str;
36 SystemTimeToHttpDate(st, str);
37 m_cookieattribs[name].expire = str;
40 return true;
43 void CWebClientSocket::Clear()
45 m_hdr.Empty();
46 m_hdrlines.RemoveAll();
47 m_data.Empty();
49 m_cmd.Empty();
50 m_path.Empty();
51 m_ver.Empty();
52 m_get.RemoveAll();
53 m_post.RemoveAll();
54 m_cookie.RemoveAll();
55 m_request.RemoveAll();
58 void CWebClientSocket::Header()
60 if(m_cmd.IsEmpty())
62 if(m_hdr.IsEmpty()) return;
64 CAtlList<CString> lines;
65 Explode(m_hdr, lines, '\n');
66 CString str = lines.RemoveHead();
68 CAtlList<CString> sl;
69 ExplodeMin(str, sl, ' ', 3);
70 m_cmd = sl.RemoveHead().MakeUpper();
71 m_path = sl.RemoveHead();
72 m_ver = sl.RemoveHead().MakeUpper();
73 ASSERT(sl.GetCount() == 0);
75 POSITION pos = lines.GetHeadPosition();
76 while(pos)
78 Explode(lines.GetNext(pos), sl, ':', 2);
79 if(sl.GetCount() == 2)
80 m_hdrlines[sl.GetHead().MakeLower()] = sl.GetTail();
84 // remember new cookies
86 POSITION pos = m_hdrlines.GetStartPosition();
87 while(pos)
89 CString key, value;
90 m_hdrlines.GetNextAssoc(pos, key, value);
92 if(key == _T("cookie"))
94 CAtlList<CString> sl;
95 Explode(value, sl, ';');
96 POSITION pos2 = sl.GetHeadPosition();
97 while(pos2)
99 CAtlList<CString> sl2;
100 Explode(sl.GetNext(pos2), sl2, '=', 2);
101 m_cookie[sl2.GetHead()] = sl2.GetCount() == 2 ? sl2.GetTail() : _T("");
106 // start new session
108 if(!m_cookie.Lookup(_T("MPCSESSIONID"), m_sessid))
110 srand((unsigned int)time(NULL));
111 m_sessid.Format(_T("%08x"), rand()*0x12345678);
112 SetCookie(_T("MPCSESSIONID"), m_sessid);
114 else
116 // TODO: load session
119 CStringA reshdr, resbody;
121 if(m_cmd == _T("POST"))
123 CString str;
124 if(m_hdrlines.Lookup(_T("content-length"), str))
126 int len = _tcstol(str, NULL, 10);
127 str.Empty();
129 int err;
130 char c;
132 int timeout = 1000;
136 for(; len > 0 && (err = Receive(&c, 1)) > 0; len--)
138 m_data += c;
139 if(c == '\r') continue;
140 str += c;
141 if(c == '\n' || len == 1)
143 CAtlList<CString> sl;
144 Explode(AToT(UrlDecode(TToA(str))), sl, '&'); // FIXME
145 POSITION pos = sl.GetHeadPosition();
146 while(pos)
148 CAtlList<CString> sl2;
149 Explode(sl.GetNext(pos), sl2, '=', 2);
150 m_post[sl2.GetHead().MakeLower()] = sl2.GetCount() == 2 ? sl2.GetTail() : _T("");
152 str.Empty();
156 if(err == SOCKET_ERROR)
157 Sleep(1);
159 while(err == SOCKET_ERROR && GetLastError() == WSAEWOULDBLOCK
160 && timeout-- > 0); // FIXME: this is just a dirty fix now
162 // FIXME: with IE it will only work if I read +2 bytes (?), btw Receive will just return -1
163 Receive(&c, 1);
164 Receive(&c, 1);
168 if(m_cmd == _T("GET") || m_cmd == _T("HEAD") || m_cmd == _T("POST"))
170 CAtlList<CString> sl;
172 Explode(m_path, sl, '?', 2);
173 m_path = sl.RemoveHead();
174 m_query.Empty();
176 if(!sl.IsEmpty())
178 m_query = sl.GetTail();
180 Explode(Explode(m_query, sl, '#', 2), sl, '&'); // oh yeah
181 // Explode(AToT(UrlDecode(TToA(Explode(m_query, sl, '#', 2)))), sl, '&'); // oh yeah
182 POSITION pos = sl.GetHeadPosition();
183 while(pos)
185 CAtlList<CString> sl2;
186 Explode(AToT(UrlDecode(TToA(sl.GetNext(pos)))), sl2, '=', 2);
187 // Explode(sl.GetNext(pos), sl2, '=', 2);
188 m_get[sl2.GetHead()] = sl2.GetCount() == 2 ? sl2.GetTail() : _T("");
192 // m_request <-- m_get+m_post+m_cookie
194 CString key, value;
195 POSITION pos;
196 pos = m_get.GetStartPosition();
197 while(pos) {m_get.GetNextAssoc(pos, key, value); m_request[key] = value;}
198 pos = m_post.GetStartPosition();
199 while(pos) {m_post.GetNextAssoc(pos, key, value); m_request[key] = value;}
200 pos = m_cookie.GetStartPosition();
201 while(pos) {m_cookie.GetNextAssoc(pos, key, value); m_request[key] = value;}
204 m_pWebServer->OnRequest(this, reshdr, resbody);
206 else
208 reshdr = "HTTP/1.0 400 Bad Request\r\n";
211 if(!reshdr.IsEmpty())
213 // cookies
215 POSITION pos = m_cookie.GetStartPosition();
216 while(pos)
218 CString key, value;
219 m_cookie.GetNextAssoc(pos, key, value);
220 reshdr += "Set-Cookie: " + key + "=" + value;
221 POSITION pos2 = m_cookieattribs.GetStartPosition();
222 while(pos2)
224 CString key;
225 cookie_attribs value;
226 m_cookieattribs.GetNextAssoc(pos2, key, value);
227 if(!value.path.IsEmpty()) reshdr += " path=" + value.path;
228 if(!value.expire.IsEmpty()) reshdr += " expire=" + value.expire;
229 if(!value.domain.IsEmpty()) reshdr += " domain=" + value.domain;
231 reshdr += "\r\n";
235 reshdr +=
236 "Server: MPC WebServer\r\n"
237 "Connection: close\r\n"
238 "\r\n";
240 Send(reshdr, reshdr.GetLength());
242 if(m_cmd != _T("HEAD") && reshdr.Find("HTTP/1.0 200 OK") == 0 && !resbody.IsEmpty())
244 Send(resbody, resbody.GetLength());
247 CString connection = _T("close");
248 m_hdrlines.Lookup(_T("connection"), connection);
250 Clear();
252 // TODO
253 // if(connection == _T("close"))
254 OnClose(0);
260 void CWebClientSocket::OnReceive(int nErrorCode)
262 if(nErrorCode == 0)
264 char c;
265 while(Receive(&c, 1) > 0)
267 if(c == '\r') continue;
268 else m_hdr += c;
270 int len = m_hdr.GetLength();
271 if(len >= 2 && m_hdr[len-2] == '\n' && m_hdr[len-1] == '\n')
273 Header();
274 return;
279 __super::OnReceive(nErrorCode);
282 void CWebClientSocket::OnClose(int nErrorCode)
284 // TODO: save session
285 m_pWebServer->OnClose(this);
286 __super::OnClose(nErrorCode);
289 ////////////////////
291 bool CWebClientSocket::OnCommand(CStringA& hdr, CStringA& body, CStringA& mime)
293 CString arg;
294 if(m_request.Lookup(_T("wm_command"), arg))
296 int id = _ttol(arg);
298 if(id > 0)
300 if(id == ID_FILE_EXIT) m_pMainFrame->PostMessage(WM_COMMAND, id);
301 else m_pMainFrame->SendMessage(WM_COMMAND, id);
303 else
305 if(arg == CMD_SETPOS && m_request.Lookup(_T("position"), arg))
307 int h, m, s, ms = 0;
308 TCHAR c;
309 if(_stscanf(arg, _T("%d%c%d%c%d%c%d"), &h, &c, &m, &c, &s, &c, &ms) >= 5)
311 REFERENCE_TIME rtPos = 10000i64*(((h*60+m)*60+s)*1000+ms);
312 m_pMainFrame->SeekTo(rtPos);
313 for(int retries = 20; retries-- > 0; Sleep(50))
315 if(abs((int)((rtPos - m_pMainFrame->GetPos())/10000)) < 100)
316 break;
320 else if(arg == CMD_SETPOS && m_request.Lookup(_T("percent"), arg))
322 float percent = 0;
323 if(_stscanf(arg, _T("%f"), &percent) == 1)
324 m_pMainFrame->SeekTo((REFERENCE_TIME)(percent / 100 * m_pMainFrame->GetDur()));
326 else if(arg == CMD_SETVOLUME && m_request.Lookup(_T("volume"), arg))
328 int volume = _tcstol(arg, NULL, 10);
329 m_pMainFrame->m_wndToolBar.Volume = min(max(volume, 1), 100);
330 m_pMainFrame->OnPlayVolume(0);
335 CString ref;
336 if(!m_hdrlines.Lookup(_T("referer"), ref))
337 return true;
339 hdr =
340 "HTTP/1.0 302 Found\r\n"
341 "Location: " + CStringA(ref) + "\r\n";
343 return true;
346 bool CWebClientSocket::OnIndex(CStringA& hdr, CStringA& body, CStringA& mime)
348 CStringA wmcoptions;
350 // generate page
352 AppSettings& s = AfxGetAppSettings();
353 POSITION pos = s.wmcmds.GetHeadPosition();
354 while(pos)
356 wmcmd& wc = s.wmcmds.GetNext(pos);
357 CStringA str;
358 str.Format("%d", wc.cmd);
359 wmcoptions += "<option value=\"" + str + "\">"
360 + CStringA(wc.name) + "\r\n";
363 m_pWebServer->LoadPage(IDR_HTML_INDEX, body, m_path);
364 body.Replace("[wmcoptions]", wmcoptions);
366 return true;
369 bool CWebClientSocket::OnBrowser(CStringA& hdr, CStringA& body, CStringA& mime)
371 CAtlList<CStringA> rootdrives;
372 for(TCHAR drive[] = _T("A:"); drive[0] <= 'Z'; drive[0]++)
373 if(GetDriveType(drive) != DRIVE_NO_ROOT_DIR)
374 rootdrives.AddTail(CStringA(drive) + '\\');
376 // process GET
378 CString path;
379 CFileStatus fs;
380 if(m_get.Lookup(_T("path"), path))
382 path = WToT(UTF8To16(TToA(path)));
384 if(CFileGetStatus(path, fs) && !(fs.m_attribute&CFile::directory))
386 // TODO: make a new message for just opening files, this is a bit overkill now...
388 CAtlList<CString> cmdln;
390 cmdln.AddTail(path);
392 CString focus;
393 if(m_get.Lookup(_T("focus"), focus) && !focus.CompareNoCase(_T("no")))
394 cmdln.AddTail(_T("/nofocus"));
396 int len = 0;
398 POSITION pos = cmdln.GetHeadPosition();
399 while(pos)
401 CString& str = cmdln.GetNext(pos);
402 len += (str.GetLength()+1)*sizeof(TCHAR);
405 CAutoVectorPtr<BYTE> buff;
406 if(buff.Allocate(4+len))
408 BYTE* p = buff;
409 *(DWORD*)p = cmdln.GetCount();
410 p += sizeof(DWORD);
412 POSITION pos = cmdln.GetHeadPosition();
413 while(pos)
415 CString& str = cmdln.GetNext(pos);
416 len = (str.GetLength()+1)*sizeof(TCHAR);
417 memcpy(p, (LPCTSTR)str, len);
418 p += len;
421 COPYDATASTRUCT cds;
422 cds.dwData = 0x6ABE51;
423 cds.cbData = p - buff;
424 cds.lpData = (void*)(BYTE*)buff;
425 m_pMainFrame->SendMessage(WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds);
428 CPath p(path);
429 p.RemoveFileSpec();
430 path = (LPCTSTR)p;
433 else
435 path = m_pMainFrame->m_wndPlaylistBar.GetCur();
437 if(CFileGetStatus(path, fs) && !(fs.m_attribute&CFile::directory))
439 CPath p(path);
440 p.RemoveFileSpec();
441 path = (LPCTSTR)p;
445 if(path.Find(_T("://")) >= 0)
446 path.Empty();
448 if(CFileGetStatus(path, fs) && (fs.m_attribute&CFile::directory)
449 || path.Find(_T("\\")) == 0) // FIXME
451 CPath p(path);
452 p.Canonicalize();
453 p.MakePretty();
454 p.AddBackslash();
455 path = (LPCTSTR)p;
458 CStringA files;
460 if(path.IsEmpty())
462 POSITION pos = rootdrives.GetHeadPosition();
463 while(pos)
465 CStringA& drive = rootdrives.GetNext(pos);
467 files += "<tr class=\"dir\">\r\n";
468 files +=
469 "<td class=\"dirname\"><a href=\"[path]?path=" + UrlEncode(drive) + "\">" + drive + "</a></td>"
470 "<td class=\"dirtype\">Directory</td>"
471 "<td class=\"dirsize\">&nbsp</td>\r\n"
472 "<td class=\"dirdate\">&nbsp</td>";
473 files += "</tr>\r\n";
476 path = "Root";
478 else
480 CString parent;
482 if(path.GetLength() > 3)
484 CPath p(path + "..");
485 p.Canonicalize();
486 p.AddBackslash();
487 parent = (LPCTSTR)p;
490 files += "<tr class=\"dir\">\r\n";
491 files +=
492 "<td class=\"dirname\"><a href=\"[path]?path=" + parent + "\">..</a></td>"
493 "<td class=\"dirtype\">Directory</td>"
494 "<td class=\"dirsize\">&nbsp</td>\r\n"
495 "<td class=\"dirdate\">&nbsp</td>";
496 files += "</tr>\r\n";
498 WIN32_FIND_DATA fd = {0};
500 HANDLE hFind = FindFirstFile(path + "*.*", &fd);
501 if(hFind != INVALID_HANDLE_VALUE)
505 if(!(fd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) || fd.cFileName[0] == '.')
506 continue;
508 CString fullpath = path + fd.cFileName;
510 files += "<tr class=\"dir\">\r\n";
511 files +=
512 "<td class=\"dirname\"><a href=\"[path]?path=" + UTF8Arg(fullpath) + "\">" + UTF8(fd.cFileName) + "</a></td>"
513 "<td class=\"dirtype\">Directory</td>"
514 "<td class=\"dirsize\">&nbsp</td>\r\n"
515 "<td class=\"dirdate\"><nobr>" + CStringA(CTime(fd.ftLastWriteTime).Format(_T("%Y.%m.%d %H:%M"))) + "</nobr></td>";
516 files += "</tr>\r\n";
518 while(FindNextFile(hFind, &fd));
520 FindClose(hFind);
523 hFind = FindFirstFile(path + "*.*", &fd);
524 if(hFind != INVALID_HANDLE_VALUE)
528 if(fd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
529 continue;
531 CString fullpath = path + fd.cFileName;
532 TCHAR *ext = _tcsrchr(fd.cFileName, '.');
533 if (ext != NULL) ext++;
535 CStringA size;
536 size.Format("%I64dK", ((UINT64)fd.nFileSizeHigh<<22)|(fd.nFileSizeLow>>10));
538 CString type(_T("&nbsp"));
539 LoadType(fullpath, type);
541 if (ext != NULL)
542 files += "<tr class=\"" + UTF8(ext) + "\">\r\n";
543 else
544 files += "<tr class=\"noext\">\r\n";
545 files +=
546 "<td class=\"filename\"><a href=\"[path]?path=" + UTF8Arg(fullpath) + "\">" + UTF8(fd.cFileName) + "</a></td>"
547 "<td class=\"filetype\"><nobr>" + UTF8(type) + "</nobr></td>"
548 "<td class=\"filesize\" align=\"right\"><nobr>" + size + "</nobr></td>\r\n"
549 "<td class=\"filedate\"><nobr>" + CStringA(CTime(fd.ftLastWriteTime).Format(_T("%Y.%m.%d %H:%M"))) + "</nobr></td>";
550 files += "</tr>\r\n";
552 while(FindNextFile(hFind, &fd));
554 FindClose(hFind);
558 m_pWebServer->LoadPage(IDR_HTML_BROWSER, body, m_path);
559 body.Replace("[charset]", "UTF-8"); // FIXME: win9x build...
560 body.Replace("[currentdir]", UTF8(path));
561 body.Replace("[currentfiles]", files);
563 return true;
566 bool CWebClientSocket::OnControls(CStringA& hdr, CStringA& body, CStringA& mime)
568 CString path = m_pMainFrame->m_wndPlaylistBar.GetCur();
569 CString dir;
571 if(!path.IsEmpty())
573 CPath p(path);
574 p.RemoveFileSpec();
575 dir = (LPCTSTR)p;
578 OAFilterState fs = m_pMainFrame->GetMediaState();
579 CString state;
580 state.Format(_T("%d"), fs);
581 CString statestring;
582 switch(fs)
584 case State_Stopped: statestring = ResStr(IDS_CONTROLS_STOPPED); break;
585 case State_Paused: statestring = ResStr(IDS_CONTROLS_PAUSED); break;
586 case State_Running: statestring = ResStr(IDS_CONTROLS_PLAYING); break;
587 default: statestring = _T("n/a"); break;
590 int pos = (int)(m_pMainFrame->GetPos()/10000);
591 int dur = (int)(m_pMainFrame->GetDur()/10000);
593 CString position, duration;
594 position.Format(_T("%d"), pos);
595 duration.Format(_T("%d"), dur);
597 CString positionstring, durationstring, playbackrate;
598 // positionstring.Format(_T("%02d:%02d:%02d.%03d"), (pos/3600000), (pos/60000)%60, (pos/1000)%60, pos%1000);
599 // durationstring.Format(_T("%02d:%02d:%02d.%03d"), (dur/3600000), (dur/60000)%60, (dur/1000)%60, dur%1000);
600 positionstring.Format(_T("%02d:%02d:%02d"), (pos/3600000), (pos/60000)%60, (pos/1000)%60);
601 durationstring.Format(_T("%02d:%02d:%02d"), (dur/3600000), (dur/60000)%60, (dur/1000)%60);
602 playbackrate = _T("1"); // TODO
604 CString volumelevel, muted;
605 volumelevel.Format(_T("%d"), m_pMainFrame->m_wndToolBar.m_volctrl.GetPos());
606 muted.Format(_T("%d"), m_pMainFrame->m_wndToolBar.Volume == -10000 ? 1 : 0);
608 CString reloadtime(_T("0")); // TODO
610 m_pWebServer->LoadPage(IDR_HTML_CONTROLS, body, m_path);
611 body.Replace("[charset]", "UTF-8"); // FIXME: win9x build...
612 body.Replace("[filepatharg]", UTF8Arg(path));
613 body.Replace("[filepath]", UTF8(path));
614 body.Replace("[filedirarg]", UTF8Arg(dir));
615 body.Replace("[filedir]", UTF8(dir));
616 body.Replace("[state]", UTF8(state));
617 body.Replace("[statestring]", UTF8(statestring));
618 body.Replace("[position]", UTF8(position));
619 body.Replace("[positionstring]", UTF8(positionstring));
620 body.Replace("[duration]", UTF8(duration));
621 body.Replace("[durationstring]", UTF8(durationstring));
622 body.Replace("[volumelevel]", UTF8(volumelevel));
623 body.Replace("[muted]", UTF8(muted));
624 body.Replace("[playbackrate]", UTF8(playbackrate));
625 body.Replace("[reloadtime]", UTF8(reloadtime));
627 return true;
630 bool CWebClientSocket::OnStatus(CStringA& hdr, CStringA& body, CStringA& mime)
633 CString path = m_pMainFrame->m_wndPlaylistBar.GetCur(), dir;
634 if(!path.IsEmpty()) {CPath p(path); p.RemoveFileSpec(); dir = (LPCTSTR)p;}
635 path.Replace(_T("'"), _T("\\'"));
636 dir.Replace(_T("'"), _T("\\'"));
638 CString volumelevel, muted;
639 volumelevel.Format(_T("%d"), m_pMainFrame->m_wndToolBar.m_volctrl.GetPos());
640 muted.Format(_T("%d"), m_pMainFrame->m_wndToolBar.Volume == -10000 ? 1 : 0);
641 body.Replace("[volumelevel]", UTF8(volumelevel));
642 body.Replace("[muted]", UTF8(muted));
644 CString title;
645 m_pMainFrame->GetWindowText(title);
647 CString status = m_pMainFrame->GetStatusMessage();
649 int pos = (int)(m_pMainFrame->GetPos()/10000);
650 int dur = (int)(m_pMainFrame->GetDur()/10000);
652 CString posstr, durstr;
653 posstr.Format(_T("%02d:%02d:%02d"), (pos/3600000), (pos/60000)%60, (pos/1000)%60);
654 durstr.Format(_T("%02d:%02d:%02d"), (dur/3600000), (dur/60000)%60, (dur/1000)%60);
656 title.Replace(_T("'"), _T("\\'"));
657 status.Replace(_T("'"), _T("\\'"));
659 body.Format("OnStatus('%s', '%s', %d, '%s', %d, '%s', %d, %d)", // , '%s', '%s'
660 UTF8(title), UTF8(status),
661 pos, UTF8(posstr), dur, UTF8(durstr),
662 m_pMainFrame->IsMuted(), m_pMainFrame->GetVolume()
663 /*, UTF8(path), UTF8(dir)*/);
665 return true;
668 bool CWebClientSocket::OnError404(CStringA& hdr, CStringA& body, CStringA& mime)
670 m_pWebServer->LoadPage(IDR_HTML_404, body, m_path);
671 return true;
674 bool CWebClientSocket::OnPlayer(CStringA& hdr, CStringA& body, CStringA& mime)
676 m_pWebServer->LoadPage(IDR_HTML_PLAYER, body, m_path);
677 return true;
680 #include "jpeg.h"
682 bool CWebClientSocket::OnSnapShotJpeg(CStringA& hdr, CStringA& body, CStringA& mime)
684 // TODO: add quality control and return logo when nothing is loaded
686 bool fRet = false;
688 BYTE* pData = NULL;
689 long size = 0;
690 CAtlArray<BYTE> jpeg;
691 if(m_pMainFrame->GetDIB(&pData, size, true))
693 if(CJpegEncoderMem().Encode(pData, jpeg))
695 hdr +=
696 "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n"
697 "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n"
698 "Pragma: no-cache\r\n";
699 body = CStringA((char*)jpeg.GetData(), jpeg.GetCount());
700 mime = "image/jpeg";
701 fRet = true;
704 delete [] pData;
707 return fRet;
710 #include "ConvertDlg.h"
712 bool CWebClientSocket::OnConvRes(CStringA& hdr, CStringA& body, CStringA& mime)
714 CString id;
715 if(!m_get.Lookup(_T("id"), id))
716 return false;
718 DWORD key = 0;
719 if(1 != _stscanf(id, _T("%x"), &key) || key == 0)
720 return false;
722 CAutoLock cAutoLock(&CDSMResource::m_csResources);
724 CDSMResource* res = NULL;
725 if(!CDSMResource::m_resources.Lookup(key, res) || !res)
726 return false;
728 body = CStringA((const char*)res->data.GetData(), res->data.GetCount());
729 mime = CString(res->mime);
731 return true;