summaryrefslogtreecommitdiff
path: root/protocols/NewsAggregator
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/NewsAggregator')
-rw-r--r--protocols/NewsAggregator/NewsAggregator.vcxproj28
-rw-r--r--protocols/NewsAggregator/NewsAggregator.vcxproj.filters4
-rw-r--r--protocols/NewsAggregator/Res/AddFeed.icobin0 -> 1150 bytes
-rw-r--r--protocols/NewsAggregator/Res/CheckALL.icobin0 -> 1150 bytes
-rw-r--r--protocols/NewsAggregator/Res/Disabled.icobin0 -> 1150 bytes
-rw-r--r--protocols/NewsAggregator/Res/Enabled.icobin0 -> 1150 bytes
-rw-r--r--protocols/NewsAggregator/Res/Export.icobin0 -> 1150 bytes
-rw-r--r--protocols/NewsAggregator/Res/Import.icobin0 -> 1150 bytes
-rw-r--r--protocols/NewsAggregator/Res/Main.icobin0 -> 5430 bytes
-rw-r--r--protocols/NewsAggregator/Res/Resource.rc184
-rw-r--r--protocols/NewsAggregator/Res/Version.rc9
-rw-r--r--protocols/NewsAggregator/Src/Authentication.cpp101
-rw-r--r--protocols/NewsAggregator/Src/CheckFeed.cpp473
-rw-r--r--protocols/NewsAggregator/Src/Icons.cpp53
-rw-r--r--protocols/NewsAggregator/Src/Menus.cpp83
-rw-r--r--protocols/NewsAggregator/Src/NewsAggregator.cpp106
-rw-r--r--protocols/NewsAggregator/Src/Options.cpp1016
-rw-r--r--protocols/NewsAggregator/Src/Options.h162
-rw-r--r--protocols/NewsAggregator/Src/Services.cpp261
-rw-r--r--protocols/NewsAggregator/Src/Update.cpp139
-rw-r--r--protocols/NewsAggregator/Src/Utils.cpp445
-rw-r--r--protocols/NewsAggregator/Src/resource.h57
-rw-r--r--protocols/NewsAggregator/Src/stdafx.cxx18
-rw-r--r--protocols/NewsAggregator/Src/stdafx.h167
-rw-r--r--protocols/NewsAggregator/Src/version.h13
-rw-r--r--protocols/NewsAggregator/docs/AtomText.txt482
-rw-r--r--protocols/NewsAggregator/docs/RssText.txt713
-rw-r--r--protocols/NewsAggregator/docs/ToDo.txt11
-rw-r--r--protocols/NewsAggregator/docs/subscriptions_test.xml169
-rw-r--r--protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj28
-rw-r--r--protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj.filters4
-rw-r--r--protocols/NewsAggregator/proto_newsaggregator/res/Offline.icobin0 -> 5430 bytes
-rw-r--r--protocols/NewsAggregator/proto_newsaggregator/res/Online.icobin0 -> 5430 bytes
-rw-r--r--protocols/NewsAggregator/proto_newsaggregator/res/Proto_NewsAggregator.rc70
-rw-r--r--protocols/NewsAggregator/proto_newsaggregator/src/resource.h17
35 files changed, 4813 insertions, 0 deletions
diff --git a/protocols/NewsAggregator/NewsAggregator.vcxproj b/protocols/NewsAggregator/NewsAggregator.vcxproj
new file mode 100644
index 0000000000..3b427aec7d
--- /dev/null
+++ b/protocols/NewsAggregator/NewsAggregator.vcxproj
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>NewsAggregator</ProjectName>
+ <ProjectGuid>{6DE11A47-2268-4B08-8DE5-15A1705FCE28}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\plugin.props" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/NewsAggregator/NewsAggregator.vcxproj.filters b/protocols/NewsAggregator/NewsAggregator.vcxproj.filters
new file mode 100644
index 0000000000..5ef6c526f1
--- /dev/null
+++ b/protocols/NewsAggregator/NewsAggregator.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/NewsAggregator/Res/AddFeed.ico b/protocols/NewsAggregator/Res/AddFeed.ico
new file mode 100644
index 0000000000..6a7e9af31e
--- /dev/null
+++ b/protocols/NewsAggregator/Res/AddFeed.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/CheckALL.ico b/protocols/NewsAggregator/Res/CheckALL.ico
new file mode 100644
index 0000000000..9a720c2e07
--- /dev/null
+++ b/protocols/NewsAggregator/Res/CheckALL.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/Disabled.ico b/protocols/NewsAggregator/Res/Disabled.ico
new file mode 100644
index 0000000000..1055879373
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Disabled.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/Enabled.ico b/protocols/NewsAggregator/Res/Enabled.ico
new file mode 100644
index 0000000000..b62ed83376
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Enabled.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/Export.ico b/protocols/NewsAggregator/Res/Export.ico
new file mode 100644
index 0000000000..945815b772
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Export.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/Import.ico b/protocols/NewsAggregator/Res/Import.ico
new file mode 100644
index 0000000000..bbe29ca82f
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Import.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/Main.ico b/protocols/NewsAggregator/Res/Main.ico
new file mode 100644
index 0000000000..75c9ff1aa3
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Main.ico
Binary files differ
diff --git a/protocols/NewsAggregator/Res/Resource.rc b/protocols/NewsAggregator/Res/Resource.rc
new file mode 100644
index 0000000000..eb7688640f
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Resource.rc
@@ -0,0 +1,184 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian (Russia) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+#pragma code_page(1251)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON ICON "Main.ico"
+IDI_CHECKALL ICON "CheckAll.ico"
+IDI_ADDFEED ICON "AddFeed.ico"
+IDI_IMPORTFEEDS ICON "Import.ico"
+IDI_EXPORTFEEDS ICON "Export.ico"
+IDI_ENABLED ICON "Enabled.ico"
+IDI_DISABLED ICON "Disabled.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPTIONS DIALOGEX 0, 0, 314, 234
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_FEEDLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,9,8,294,174
+ PUSHBUTTON "Add",IDC_ADD,79,187,50,14
+ PUSHBUTTON "Change",IDC_CHANGE,133,187,50,14
+ PUSHBUTTON "Remove",IDC_REMOVE,187,187,50,14
+ PUSHBUTTON "Import",IDC_IMPORT,252,204,50,14
+ PUSHBUTTON "Export",IDC_EXPORT,252,219,50,14
+ CONTROL "Retrieve news at startup",IDC_STARTUPRETRIEVE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,9,205,203,10
+END
+
+IDD_ADDFEED DIALOGEX 0, 0, 250, 228
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_NOFAILCREATE | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,140,209,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,194,209,50,14
+ GROUPBOX "General Settings",IDC_STATIC,6,3,238,61
+ RTEXT "Title",IDC_STATIC,17,16,44,8
+ EDITTEXT IDC_FEEDTITLE,63,14,173,13,ES_AUTOHSCROLL
+ RTEXT "URL",IDC_STATIC,17,31,44,8
+ EDITTEXT IDC_FEEDURL,63,29,173,13,ES_AUTOHSCROLL
+ RTEXT "Check every",IDC_STATIC,7,46,54,8
+ LTEXT "minutes",IDC_STATIC,100,46,75,8
+ PUSHBUTTON "Check Feed",IDC_DISCOVERY,177,44,59,12
+ GROUPBOX "Authentication",IDC_STATIC,6,67,238,48
+ CONTROL "Use &authentication",IDC_USEAUTH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,80,157,10
+ RTEXT "Login",IDC_STATIC,16,96,42,8
+ EDITTEXT IDC_LOGIN,61,94,63,14,ES_AUTOHSCROLL | WS_DISABLED
+ RTEXT "Password",IDC_STATIC,129,96,41,8
+ EDITTEXT IDC_PASSWORD,173,94,63,14,ES_PASSWORD | ES_AUTOHSCROLL | WS_DISABLED
+ GROUPBOX "Visualization",IDC_STATIC,6,119,238,85
+ LTEXT "Display news using the following format:",IDC_STATIC,13,132,168,8
+ EDITTEXT IDC_TAGSEDIT,13,143,224,36,ES_MULTILINE | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL
+ LTEXT "All item's tags are valid. Put them between #. Example: #<author>#",IDC_STATIC,14,182,160,16
+ PUSHBUTTON "Reset",IDC_RESET,192,184,45,14
+ PUSHBUTTON "?",IDC_TAGHELP,175,184,15,14
+ LTEXT "0 - check manually",IDC_STATIC,100,55,78,8
+ EDITTEXT IDC_CHECKTIME,64,45,32,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_TIMEOUT_VALUE_SPIN,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,85,45,11,12
+END
+
+IDD_AUTHENTICATION DIALOGEX 0, 0, 211, 106
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Authentication"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CTEXT "Feed name",IDC_FEEDNAME,7,5,196,8
+ LTEXT "This feed seems to need authentication. Please fill username and password fields:",IDC_STATIC,7,19,196,22
+ RTEXT "Username",IDC_STATIC,25,49,42,8
+ EDITTEXT IDC_FEEDUSERNAME,71,46,80,14,ES_AUTOHSCROLL
+ RTEXT "Password",IDC_STATIC,25,66,42,8
+ EDITTEXT IDC_FEEDPASSWORD,71,63,80,14,ES_PASSWORD | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,98,87,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,153,87,50,14
+END
+
+IDD_FEEDEXPORT DIALOGEX 0, 0, 275, 138
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_ACCEPTFILES | WS_EX_CONTROLPARENT
+CAPTION "Export"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Available feeds:",IDC_STATIC,6,6,100,8
+ LTEXT "Feeds to be exported:",IDC_STATIC,150,6,98,8
+ LISTBOX IDC_FEEDSLIST,6,18,120,98,LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ LISTBOX IDC_FEEDSEXPORTLIST,150,18,120,98,LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ PUSHBUTTON "->",IDC_ADDFEED,129,24,17,14
+ PUSHBUTTON "<-",IDC_REMOVEFEED,129,40,17,14
+ PUSHBUTTON "&Export",IDOK,164,120,50,14
+ PUSHBUTTON "&Close",IDCANCEL,220,120,50,14
+ PUSHBUTTON "->>",IDC_ADDALLFEEDS,129,78,17,14
+ PUSHBUTTON "<<-",IDC_REMOVEALLFEEDS,129,95,17,14
+END
+
+IDD_FEEDIMPORT DIALOGEX 0, 0, 276, 161
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_ACCEPTFILES | WS_EX_CONTROLPARENT
+CAPTION "Import"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Import from:",IDC_STATIC,6,7,47,8
+ EDITTEXT IDC_IMPORTFILEPATH,59,5,186,14,ES_AUTOHSCROLL | ES_READONLY
+ PUSHBUTTON "...",IDC_BROWSEIMPORTFILE,248,5,22,14
+ LTEXT "Available feeds:",IDC_STATIC,6,26,100,8
+ LTEXT "Feeds to be imported:",IDC_STATIC,150,26,101,8
+ LISTBOX IDC_FEEDSLIST,6,38,120,98,LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ LISTBOX IDC_FEEDSIMPORTLIST,150,38,120,98,LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP
+ PUSHBUTTON "->",IDC_ADDFEED,129,47,17,14
+ PUSHBUTTON "<-",IDC_REMOVEFEED,129,63,17,14
+ PUSHBUTTON "&Import",IDOK,165,141,50,14
+ PUSHBUTTON "&Close",IDCANCEL,220,141,50,14
+ PUSHBUTTON "->>",IDC_ADDALLFEEDS,129,97,17,14
+ PUSHBUTTON "<<-",IDC_REMOVEALLFEEDS,129,113,17,14
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "..\\src\\resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+#endif // Russian (Russia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/NewsAggregator/Res/Version.rc b/protocols/NewsAggregator/Res/Version.rc
new file mode 100644
index 0000000000..5a5ddd63ed
--- /dev/null
+++ b/protocols/NewsAggregator/Res/Version.rc
@@ -0,0 +1,9 @@
+// Microsoft Visual C++ generated resource script.
+//
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+#include "..\src\version.h"
+
+#include "..\..\build\Version.rc"
diff --git a/protocols/NewsAggregator/Src/Authentication.cpp b/protocols/NewsAggregator/Src/Authentication.cpp
new file mode 100644
index 0000000000..35c5cb36bd
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Authentication.cpp
@@ -0,0 +1,101 @@
+/*
+Copyright (C) 2012 Mataes
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include "stdafx.h"
+
+void CreateAuthString(char *auth, MCONTACT hContact, CFeedEditor *pDlg)
+{
+ wchar_t *tlogin = nullptr, *tpass = nullptr;
+ if (hContact && g_plugin.getByte(hContact, "UseAuth")) {
+ tlogin = g_plugin.getWStringA(hContact, "Login");
+ tpass = g_plugin.getWStringA(hContact, "Password");
+ }
+ else if (pDlg && pDlg->m_useauth.IsChecked()) {
+ tlogin = pDlg->m_login.GetText();
+ tpass = pDlg->m_password.GetText();
+ }
+ char *user = mir_u2a(tlogin), *pass = mir_u2a(tpass);
+
+ char str[MAX_PATH];
+ int len = mir_snprintf(str, "%s:%s", user, pass);
+ mir_free(user);
+ mir_free(pass);
+ mir_free(tlogin);
+ mir_free(tpass);
+
+ mir_snprintf(auth, 250, "Basic %s", ptrA(mir_base64_encode(str, (size_t)len)));
+}
+
+CAuthRequest::CAuthRequest(CFeedEditor *pDlg, MCONTACT hContact) :
+ CSuper(g_plugin, IDD_AUTHENTICATION),
+ m_feedname(this, IDC_FEEDNAME), m_username(this, IDC_FEEDUSERNAME),
+ m_password(this, IDC_FEEDPASSWORD), m_ok(this, IDOK)
+{
+ m_pDlg = pDlg;
+ m_hContact = hContact;
+ m_ok.OnClick = Callback(this, &CAuthRequest::OnOk);
+}
+
+bool CAuthRequest::OnInitDialog()
+{
+ if (m_pDlg) {
+ ptrW strfeedtitle(m_pDlg->m_feedtitle.GetText());
+
+ if (strfeedtitle)
+ m_feedname.SetText(strfeedtitle);
+ else {
+ ptrW strfeedurl(m_pDlg->m_feedurl.GetText());
+ m_feedname.SetText(strfeedurl);
+ }
+ }
+ else if (m_hContact) {
+ ptrW ptszNick(g_plugin.getWStringA(m_hContact, "Nick"));
+ if (!ptszNick)
+ ptszNick = g_plugin.getWStringA(m_hContact, "URL");
+ if (ptszNick)
+ m_feedname.SetText(ptszNick);
+ }
+ return true;
+}
+
+void CAuthRequest::OnOk(CCtrlBase*)
+{
+ ptrW strfeedusername(m_username.GetText());
+ if (!strfeedusername || mir_wstrcmp(strfeedusername, L"") == 0) {
+ MessageBox(m_hwnd, TranslateT("Enter your username"), TranslateT("Error"), MB_OK | MB_ICONERROR);
+ return;
+ }
+ ptrA strfeedpassword(m_password.GetTextA());
+ if (!strfeedpassword || mir_strcmp(strfeedpassword, "") == 0) {
+ MessageBox(m_hwnd, TranslateT("Enter your password"), TranslateT("Error"), MB_OK | MB_ICONERROR);
+ return;
+ }
+ if (m_pDlg) {
+ m_pDlg->m_useauth.SetState(1);
+ m_pDlg->m_login.Enable(1);
+ m_pDlg->m_password.Enable(1);
+ m_pDlg->m_login.SetText(strfeedusername);
+ m_pDlg->m_password.SetTextA(strfeedpassword);
+ }
+ else if (m_hContact) {
+ g_plugin.setByte(m_hContact, "UseAuth", 1);
+ g_plugin.setWString(m_hContact, "Login", strfeedusername);
+ g_plugin.setString(m_hContact, "Password", strfeedpassword);
+ }
+}
diff --git a/protocols/NewsAggregator/Src/CheckFeed.cpp b/protocols/NewsAggregator/Src/CheckFeed.cpp
new file mode 100644
index 0000000000..87282451f4
--- /dev/null
+++ b/protocols/NewsAggregator/Src/CheckFeed.cpp
@@ -0,0 +1,473 @@
+/*
+Copyright (C) 2012 Mataes
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include "stdafx.h"
+
+static CMStringA DetectEncoding(const TiXmlDocument &doc)
+{
+ auto *pChild = doc.FirstChild();
+ if (pChild)
+ if (auto *pDecl = pChild->ToDeclaration())
+ if (auto *pVal = pDecl->Value())
+ if (!memcmp(pVal, "xml", 3)) {
+ const char *p1 = strstr(pVal, "encoding=\""), *p2 = 0;
+ if (p1) {
+ p1 += 10;
+ p2 = strchr(p1, '\"');
+ }
+ if (p1 && p2)
+ return CMStringA(p1, int(p2-p1));
+ }
+
+ return CMStringA();
+}
+
+static wchar_t* EncodeResult(const char *szString, const CMStringA &szEncoding)
+{
+ if (szEncoding == "koi8-r")
+ return mir_a2u_cp(szString, 20866);
+ if (szEncoding == "windows-1251")
+ return mir_a2u_cp(szString, 1251);
+
+ return mir_utf8decodeW(szString);
+}
+
+static void SetAvatar(MCONTACT hContact, const char *pszValue)
+{
+ Utf2T url(pszValue);
+ g_plugin.setWString(hContact, "ImageURL", url);
+
+ PROTO_AVATAR_INFORMATION ai = { 0 };
+ ai.hContact = hContact;
+
+ ptrW szNick(g_plugin.getWStringA(hContact, "Nick"));
+ if (szNick) {
+ wchar_t *ext = wcsrchr((wchar_t *)url, '.') + 1;
+ ai.format = ProtoGetAvatarFormat(ext);
+
+ wchar_t *filename = szNick;
+ mir_snwprintf(ai.filename, L"%s\\%s.%s", tszRoot, filename, ext);
+ if (DownloadFile(url, ai.filename)) {
+ g_plugin.setWString(hContact, "ImagePath", ai.filename);
+ ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, (HANDLE)&ai, NULL);
+ }
+ else ProtoBroadcastAck(MODULENAME, hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, (HANDLE)&ai, NULL);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// touches a feed to verify whether it exists
+
+LPCTSTR CheckFeed(wchar_t *tszURL, CFeedEditor *pEditDlg)
+{
+ Netlib_LogfW(hNetlibUser, L"Started validating feed %s.", tszURL);
+ char *szData = nullptr;
+ GetNewsData(tszURL, &szData, NULL, pEditDlg);
+ if (szData) {
+ TiXmlDocument doc;
+ int ret = doc.Parse(szData);
+ mir_free(szData);
+ if (ret == ERROR_SUCCESS) {
+ CMStringA codepage = DetectEncoding(doc);
+
+ for (auto *it : TiXmlEnum(&doc)) {
+ auto *szNodeName = it->Name();
+ const TiXmlElement *pNode;
+ if (!mir_strcmpi(szNodeName, "rss") || !mir_strcmpi(szNodeName, "rdf"))
+ pNode = it->FirstChildElement();
+ else if (!mir_strcmpi(szNodeName, "feed"))
+ pNode = it;
+ else continue;
+
+ for (auto *child : TiXmlFilter(pNode, "title")) {
+ wchar_t mes[MAX_PATH];
+ mir_snwprintf(mes, TranslateT("%s\nis a valid feed's address."), tszURL);
+ MessageBox(pEditDlg->GetHwnd(), mes, TranslateT("News Aggregator"), MB_OK | MB_ICONINFORMATION);
+ return EncodeResult(child->GetText(), codepage);
+ }
+ }
+ }
+ }
+
+ Netlib_LogfW(hNetlibUser, L"%s is not a valid feed's address.", tszURL);
+ wchar_t mes[MAX_PATH];
+ mir_snwprintf(mes, TranslateT("%s\nis not a valid feed's address."), tszURL);
+ MessageBox(pEditDlg->GetHwnd(), mes, TranslateT("News Aggregator"), MB_OK | MB_ICONERROR);
+ return nullptr;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// loads a feed completely, with messages
+
+static void XmlToMsg(MCONTACT hContact, CMStringW &title, CMStringW &link, CMStringW &descr, CMStringW &author, CMStringW &comments, CMStringW &guid, CMStringW &category, time_t stamp)
+{
+ CMStringW message = g_plugin.getWStringA(hContact, "MsgFormat");
+ if (!message)
+ message = TAGSDEFAULT;
+
+ if (title.IsEmpty())
+ message.Replace(L"#<title>#", TranslateT("empty"));
+ else
+ message.Replace(L"#<title>#", title);
+
+ if (link.IsEmpty())
+ message.Replace(L"#<link>#", TranslateT("empty"));
+ else
+ message.Replace(L"#<link>#", link);
+
+ if (descr.IsEmpty())
+ message.Replace(L"#<description>#", TranslateT("empty"));
+ else
+ message.Replace(L"#<description>#", descr);
+
+ if (author.IsEmpty())
+ message.Replace(L"#<author>#", TranslateT("empty"));
+ else
+ message.Replace(L"#<author>#", author);
+
+ if (comments.IsEmpty())
+ message.Replace(L"#<comments>#", TranslateT("empty"));
+ else
+ message.Replace(L"#<comments>#", comments);
+
+ if (guid.IsEmpty())
+ message.Replace(L"#<guid>#", TranslateT("empty"));
+ else
+ message.Replace(L"#<guid>#", guid);
+
+ if (category.IsEmpty())
+ message.Replace(L"#<category>#", TranslateT("empty"));
+ else
+ message.Replace(L"#<category>#", category);
+
+ DBEVENTINFO olddbei = {};
+ bool MesExist = false;
+ T2Utf pszTemp(message);
+ DWORD cbMemoLen = 10000, cbOrigLen = (DWORD)mir_strlen(pszTemp);
+ BYTE *pbBuffer = (BYTE*)mir_alloc(cbMemoLen);
+ for (MEVENT hDbEvent = db_event_last(hContact); hDbEvent; hDbEvent = db_event_prev(hContact, hDbEvent)) {
+ olddbei.cbBlob = db_event_getBlobSize(hDbEvent);
+ if (olddbei.cbBlob > cbMemoLen)
+ pbBuffer = (PBYTE)mir_realloc(pbBuffer, (size_t)(cbMemoLen = olddbei.cbBlob));
+ olddbei.pBlob = pbBuffer;
+ db_event_get(hDbEvent, &olddbei);
+
+ // there's no need to look for the elder events
+ if (stamp > 0 && olddbei.timestamp < (DWORD)stamp)
+ break;
+
+ if ((DWORD)mir_strlen((char*)olddbei.pBlob) == cbOrigLen && !mir_strcmp((char*)olddbei.pBlob, pszTemp)) {
+ MesExist = true;
+ break;
+ }
+ }
+ mir_free(pbBuffer);
+
+ if (!MesExist) {
+ if (stamp == 0)
+ stamp = time(0);
+
+ T2Utf pszMessage(message);
+
+ PROTORECVEVENT recv = { 0 };
+ recv.timestamp = (DWORD)stamp;
+ recv.szMessage = pszMessage;
+ ProtoChainRecvMsg(hContact, &recv);
+ }
+}
+
+void CheckCurrentFeed(MCONTACT hContact)
+{
+ // Check is disabled by the user?
+ if (!g_plugin.getByte(hContact, "CheckState", 1) != 0)
+ return;
+
+ wchar_t *szURL = g_plugin.getWStringA(hContact, "URL");
+ if (szURL == nullptr)
+ return;
+
+ Netlib_LogfW(hNetlibUser, L"Started checking feed %s.", szURL);
+
+ char *szData = nullptr;
+ GetNewsData(szURL, &szData, hContact, nullptr);
+ mir_free(szURL);
+
+ if (szData == nullptr)
+ return;
+
+ TiXmlDocument doc;
+ int ret = doc.Parse(szData);
+ mir_free(szData);
+ if (ret != ERROR_SUCCESS)
+ return;
+
+ CMStringA codepage = DetectEncoding(doc);
+
+ CMStringW szValue;
+
+ for (auto *it : TiXmlEnum(&doc)) {
+ auto *szNodeName = it->Name();
+ bool isRSS = !mir_strcmpi(szNodeName, "rss"), isAtom = !mir_strcmpi(szNodeName, "rdf");
+ if (isRSS || isAtom) {
+ if (isRSS) {
+ if (auto *pVersion = it->Attribute("version")) {
+ char ver[MAX_PATH];
+ mir_snprintf(ver, "RSS %s", pVersion);
+ g_plugin.setString(hContact, "MirVer", ver);
+ }
+ }
+ else if (isAtom)
+ g_plugin.setWString(hContact, "MirVer", L"RSS 1.0");
+
+ for (auto *child : TiXmlEnum(it->FirstChildElement())) {
+ auto *childName = child->Name();
+ if (!mir_strcmpi(childName, "title")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "FirstName", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(childName, "link")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "Homepage", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(childName, "description")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText) {
+ ClearText(szValue, szChildText);
+ g_plugin.setWString(hContact, "About", szValue);
+ db_set_ws(hContact, "CList", "StatusMsg", szValue);
+ }
+ }
+ else if (!mir_strcmpi(childName, "language")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "Language1", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(childName, "managingEditor")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "e-mail", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(childName, "category")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "Interest0Text", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(childName, "copyright")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ db_set_s(hContact, "UserInfo", "MyNotes", _T2A(ClearText(szValue, szChildText)));
+ }
+ else if (!mir_strcmpi(childName, "image")) {
+ for (auto *xmlImage : TiXmlFilter(child, "url"))
+ SetAvatar(hContact, xmlImage->GetText());
+ }
+ else if (!mir_strcmpi(childName, "lastBuildDate")) {
+ time_t stamp = DateToUnixTime(child->GetText(), 0);
+ double deltaupd = difftime(time(0), stamp);
+ double deltacheck = difftime(time(0), (time_t)g_plugin.getDword(hContact, "LastCheck"));
+ if (deltaupd - deltacheck >= 0) {
+ g_plugin.setDword(hContact, "LastCheck", (DWORD)time(0));
+ return;
+ }
+ }
+ else if (!mir_strcmpi(childName, "item")) {
+ CMStringW title, link, descr, author, comments, guid, category;
+ time_t stamp = 0;
+ for (auto *itemval : TiXmlEnum(child)) {
+ auto *itemName = itemval->Name();
+ ptrW value(EncodeResult(itemval->GetText(), codepage));
+
+ // We only use the first tag for now and ignore the rest.
+ if (!mir_strcmpi(itemName, "title"))
+ ClearText(title, value);
+
+ else if (!mir_strcmpi(itemName, "link"))
+ ClearText(link, value);
+
+ else if (!mir_strcmpi(itemName, "pubDate") || !mir_strcmpi(itemName, "date")) {
+ if (stamp == 0)
+ stamp = DateToUnixTime(itemval->GetText(), 0);
+ }
+ else if (!mir_strcmpi(itemName, "description") || !mir_strcmpi(itemName, "encoded"))
+ ClearText(descr, value);
+
+ else if (!mir_strcmpi(itemName, "author") || !mir_strcmpi(itemName, "creator"))
+ ClearText(author, value);
+
+ else if (!mir_strcmpi(itemName, "comments"))
+ ClearText(comments, value);
+
+ else if (!mir_strcmpi(itemName, "guid"))
+ ClearText(guid, value);
+
+ else if (!mir_strcmpi(itemName, "category"))
+ ClearText(category, value);
+ }
+
+ XmlToMsg(hContact, title, link, descr, author, comments, guid, category, stamp);
+ }
+ }
+ }
+ else if (!mir_strcmpi(szNodeName, "feed")) {
+ g_plugin.setWString(hContact, "MirVer", L"Atom 3");
+ for (auto *child : TiXmlEnum(it)) {
+ auto *szChildName = child->Name();
+ if (!mir_strcmpi(szChildName, "title")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "FirstName", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(szChildName, "link")) {
+ if (!child->Attribute("rel", "self"))
+ if (auto *pHref = child->Attribute("href"))
+ g_plugin.setWString(hContact, "Homepage", Utf2T(pHref));
+ }
+ else if (!mir_strcmpi(szChildName, "subtitle")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText) {
+ ClearText(szValue, szChildText);
+ g_plugin.setWString(hContact, "About", szValue);
+ db_set_ws(hContact, "CList", "StatusMsg", szValue);
+ }
+ }
+ else if (!mir_strcmpi(szChildName, "language")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "Language1", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(szChildName, "author")) {
+ for (auto *authorval : TiXmlFilter(child, "email")) {
+ g_plugin.setWString(hContact, "e-mail", ptrW(EncodeResult(authorval->GetText(), codepage)));
+ break;
+ }
+ }
+ else if (!mir_strcmpi(szChildName, "category")) {
+ ptrW szChildText(EncodeResult(child->GetText(), codepage));
+ if (szChildText)
+ g_plugin.setWString(hContact, "Interest0Text", ClearText(szValue, szChildText));
+ }
+ else if (!mir_strcmpi(szChildName, "icon")) {
+ for (auto *imageval : TiXmlFilter(child, "url"))
+ SetAvatar(hContact, imageval->GetText());
+ }
+ else if (!mir_strcmpi(szChildName, "updated")) {
+ time_t stamp = DateToUnixTime(child->GetText(), 1);
+ double deltaupd = difftime(time(0), stamp);
+ double deltacheck = difftime(time(0), (time_t)g_plugin.getDword(hContact, "LastCheck"));
+ if (deltaupd - deltacheck >= 0) {
+ g_plugin.setDword(hContact, "LastCheck", (DWORD)time(0));
+ return;
+ }
+ }
+ else if (!mir_strcmpi(szChildName, "entry")) {
+ CMStringW title, link, descr, author, comments, guid, category;
+ time_t stamp = 0;
+ for (auto *itemval : TiXmlEnum(child)) {
+ LPCSTR szItemName = itemval->Name();
+ if (!mir_strcmpi(szItemName, "title")) {
+ ptrW szItemText(EncodeResult(itemval->GetText(), codepage));
+ if (szItemText)
+ ClearText(title, szItemText);
+ }
+ else if (!mir_strcmpi(szItemName, "link")) {
+ if (auto *pszLink = itemval->Attribute("href"))
+ ClearText(link, ptrW(EncodeResult(pszLink, codepage)));
+ }
+ else if (!mir_strcmpi(szItemName, "updated")) {
+ if (stamp == 0)
+ stamp = DateToUnixTime(itemval->GetText(), 0);
+ }
+ else if (!mir_strcmpi(szItemName, "summary") || !mir_strcmpi(szItemName, "content")) {
+ ptrW szItemText(EncodeResult(itemval->GetText(), codepage));
+ if (szItemText)
+ ClearText(descr, szItemText);
+ }
+ else if (!mir_strcmpi(szItemName, "author")) {
+ for (auto *authorval : TiXmlFilter(itemval, "name")) {
+ ptrW szItemText(EncodeResult(authorval->GetText(), codepage));
+ if (szItemText)
+ ClearText(author, szItemText);
+ break;
+ }
+ }
+ else if (!mir_strcmpi(szItemName, "comments")) {
+ ptrW szItemText(EncodeResult(itemval->GetText(), codepage));
+ if (szItemText)
+ ClearText(comments, szItemText);
+ }
+ else if (!mir_strcmpi(szItemName, "id")) {
+ ptrW szItemText(EncodeResult(itemval->GetText(), codepage));
+ if (szItemText)
+ ClearText(guid, szItemText);
+ }
+ else if (!mir_strcmpi(szItemName, "category")) {
+ if (auto *p = itemval->Attribute("term"))
+ ClearText(link, ptrW(EncodeResult(p, codepage)));
+ }
+ }
+
+ XmlToMsg(hContact, title, link, descr, author, comments, guid, category, stamp);
+ }
+ }
+ }
+ }
+ g_plugin.setDword(hContact, "LastCheck", (DWORD)time(0));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// downloads avatars from a given feed
+
+void CheckCurrentFeedAvatar(MCONTACT hContact)
+{
+ if (!g_plugin.getByte(hContact, "CheckState", 1))
+ return;
+
+ wchar_t *szURL = g_plugin.getWStringA(hContact, "URL");
+ if (szURL == nullptr)
+ return;
+
+ char *szData = nullptr;
+ GetNewsData(szURL, &szData, hContact, nullptr);
+ mir_free(szURL);
+
+ if (szData == nullptr)
+ return;
+
+ TiXmlDocument doc;
+ int ret = doc.Parse(szData);
+ mir_free(szData);
+ if (ret != ERROR_SUCCESS)
+ return;
+
+ for (auto *it : TiXmlEnum(&doc)) {
+ auto *szNodeName = it->Name();
+ if (!mir_strcmpi(szNodeName, "rss") || !mir_strcmpi(szNodeName, "rdf")) {
+ for (auto *child : TiXmlFilter(it->FirstChildElement(), "image"))
+ for (auto *xmlImage : TiXmlFilter(child, "url"))
+ SetAvatar(hContact, xmlImage->GetText());
+ }
+ else if (!mir_strcmpi(szNodeName, "feed")) {
+ for (auto *child : TiXmlFilter(it, "icon"))
+ for (auto *xmlImage : TiXmlFilter(child, "url"))
+ SetAvatar(hContact, xmlImage->GetText());
+ }
+ }
+}
diff --git a/protocols/NewsAggregator/Src/Icons.cpp b/protocols/NewsAggregator/Src/Icons.cpp
new file mode 100644
index 0000000000..b9cdeb6166
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Icons.cpp
@@ -0,0 +1,53 @@
+/*
+Copyright (C) 2012 Mataes
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include "stdafx.h"
+
+static IconItem iconList[] =
+{
+ { LPGEN("Protocol icon"), "main", IDI_ICON},
+ { LPGEN("Check All Feeds"), "checkall", IDI_CHECKALL},
+ { LPGEN("Add Feed"), "addfeed", IDI_ADDFEED},
+ { LPGEN("Import Feeds"), "importfeeds", IDI_IMPORTFEEDS},
+ { LPGEN("Export Feeds"), "exportfeeds", IDI_EXPORTFEEDS},
+ { LPGEN("Check Feed"), "checkfeed", IDI_CHECKALL},
+ { LPGEN("Auto Update Enabled"), "enabled", IDI_ENABLED},
+ { LPGEN("Auto Update Disabled"), "disabled", IDI_DISABLED}
+};
+
+void InitIcons()
+{
+ g_plugin.registerIcon(LPGEN("News Aggregator"), iconList, MODULENAME);
+}
+
+HICON LoadIconEx(const char *name, bool big)
+{
+ char szSettingName[100];
+ mir_snprintf(szSettingName, "%s_%s", MODULENAME, name);
+ return IcoLib_GetIcon(szSettingName, big);
+}
+
+HANDLE GetIconHandle(const char *name)
+{
+ for (int i=0; i < _countof(iconList); i++)
+ if ( !mir_strcmp(iconList[i].szName, name))
+ return iconList[i].hIcolib;
+
+ return nullptr;
+}
diff --git a/protocols/NewsAggregator/Src/Menus.cpp b/protocols/NewsAggregator/Src/Menus.cpp
new file mode 100644
index 0000000000..7770e843eb
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Menus.cpp
@@ -0,0 +1,83 @@
+/*
+Copyright (C) 2012 Mataes
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include "stdafx.h"
+
+HGENMENU hService2[7];
+
+void InitMenu()
+{
+ CMenuItem mi(&g_plugin);
+ mi.flags = CMIF_UNICODE | CMIF_NOTOFFLINE;
+ mi.root = g_plugin.addRootMenu(MO_MAIN, LPGENW("News Aggregator"), 500099000);
+ Menu_ConfigureItem(mi.root, MCI_OPT_UID, "D9733E4F-1946-4390-8EB3-591E8687222E");
+
+ SET_UID(mi, 0x3ec91864, 0xefa7, 0x4994, 0xb7, 0x75, 0x6c, 0x96, 0xcb, 0x29, 0x2f, 0x93);
+ mi.position = 10100001;
+ if (g_plugin.getByte("AutoUpdate", 1))
+ mi.name.w = LPGENW("Auto Update Enabled");
+ else
+ mi.name.w = LPGENW("Auto Update Disabled");
+ mi.hIcolibItem = GetIconHandle("main");
+ mi.pszService = MS_NEWSAGGREGATOR_ENABLED;
+ hService2[0] = Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0x8076bb4d, 0x1e44, 0x43af, 0x97, 0x1e, 0x31, 0xd8, 0xa4, 0xe9, 0xb8, 0x37);
+ mi.position = 20100001;
+ mi.name.w = LPGENW("Check All Feeds");
+ mi.pszService = MS_NEWSAGGREGATOR_CHECKALLFEEDS;
+ hService2[1] = Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0xb876484d, 0x28aa, 0x4e03, 0x9e, 0x98, 0xed, 0xbc, 0xd1, 0xcf, 0x31, 0x80);
+ mi.position = 20100002;
+ mi.hIcolibItem = GetIconHandle("addfeed");
+ mi.name.w = LPGENW("Add Feed");
+ mi.pszService = MS_NEWSAGGREGATOR_ADDFEED;
+ hService2[2] = Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0x600bf2c2, 0xa974, 0x44d3, 0x98, 0xf9, 0xe6, 0x65, 0x7c, 0x1f, 0x63, 0x37);
+ mi.position = 20100003;
+ mi.hIcolibItem = GetIconHandle("importfeeds");
+ mi.name.w = LPGENW("Import Feeds");
+ mi.pszService = MS_NEWSAGGREGATOR_IMPORTFEEDS;
+ hService2[3] = Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0xc09c8119, 0x64c2, 0x49bd, 0x81, 0xf, 0x54, 0x20, 0x69, 0xd7, 0x30, 0xcf);
+ mi.position = 20100004;
+ mi.hIcolibItem = GetIconHandle("exportfeeds");
+ mi.name.w = LPGENW("Export Feeds");
+ mi.pszService = MS_NEWSAGGREGATOR_EXPORTFEEDS;
+ hService2[4] = Menu_AddMainMenuItem(&mi);
+
+ // adding contact menu items
+ SET_UID(mi, 0x92be499c, 0x928c, 0x4789, 0x8f, 0x36, 0x28, 0xa2, 0x9f, 0xb7, 0x1a, 0x97);
+ mi.root = nullptr;
+ mi.position = -0x7FFFFFFA;
+ mi.hIcolibItem = GetIconHandle("checkfeed");
+ mi.name.w = LPGENW("Check feed");
+ mi.pszService = MS_NEWSAGGREGATOR_CHECKFEED;
+ hService2[5] = Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ SET_UID(mi, 0x41a70fbc, 0x9241, 0x44c0, 0x90, 0x90, 0x87, 0xd2, 0xc5, 0x9f, 0xc9, 0xac);
+ mi.name.w = LPGENW("Change feed");
+ mi.pszService = MS_NEWSAGGREGATOR_CHANGEFEED;
+ hService2[6] = Menu_AddContactMenuItem(&mi, MODULENAME);
+
+ Menu_ModifyItem(hService2[0], nullptr, GetIconHandle(g_plugin.getByte("AutoUpdate", 1) ? "enabled" : "disabled"));
+}
diff --git a/protocols/NewsAggregator/Src/NewsAggregator.cpp b/protocols/NewsAggregator/Src/NewsAggregator.cpp
new file mode 100644
index 0000000000..8ee17dd97a
--- /dev/null
+++ b/protocols/NewsAggregator/Src/NewsAggregator.cpp
@@ -0,0 +1,106 @@
+/*
+Copyright (C) 2012 Mataes
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include "stdafx.h"
+
+HANDLE hPrebuildMenuHook = nullptr;
+CDlgBase *pAddFeedDialog = nullptr, *pImportDialog = nullptr, *pExportDialog = nullptr;
+wchar_t tszRoot[MAX_PATH] = {0};
+HANDLE hUpdateMutex;
+
+LIST<CFeedEditor> g_arFeeds(1, PtrKeySortT);
+
+CMPlugin g_plugin;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PLUGININFOEX pluginInfoEx = {
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {56CC3F29-CCBF-4546-A8BA-9856248A412A}
+ {0x56cc3f29, 0xccbf, 0x4546, {0xa8, 0xba, 0x98, 0x56, 0x24, 0x8a, 0x41, 0x2a}}
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(MODULENAME, pluginInfoEx)
+{
+ RegisterProtocol(PROTOTYPE_VIRTUAL);
+ SetUniqueId("URL");
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Load()
+{
+ // Add options hook
+ HookEvent(ME_OPT_INITIALISE, OptInit);
+ HookEvent(ME_SYSTEM_MODULESLOADED, NewsAggrInit);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, NewsAggrPreShutdown);
+
+ hUpdateMutex = CreateMutex(nullptr, FALSE, nullptr);
+
+ CreateProtoServiceFunction(MODULENAME, PS_GETNAME, NewsAggrGetName);
+ CreateProtoServiceFunction(MODULENAME, PS_GETCAPS, NewsAggrGetCaps);
+ CreateProtoServiceFunction(MODULENAME, PS_SETSTATUS, NewsAggrSetStatus);
+ CreateProtoServiceFunction(MODULENAME, PS_GETSTATUS, NewsAggrGetStatus);
+ CreateProtoServiceFunction(MODULENAME, PS_LOADICON, NewsAggrLoadIcon);
+ CreateProtoServiceFunction(MODULENAME, PSS_GETINFO, NewsAggrGetInfo);
+ CreateProtoServiceFunction(MODULENAME, PS_GETAVATARINFO, NewsAggrGetAvatarInfo);
+ CreateProtoServiceFunction(MODULENAME, PSR_MESSAGE, NewsAggrRecvMessage);
+
+ CreateServiceFunction(MS_NEWSAGGREGATOR_CHECKALLFEEDS, CheckAllFeeds);
+ CreateServiceFunction(MS_NEWSAGGREGATOR_ADDFEED, AddFeed);
+ CreateServiceFunction(MS_NEWSAGGREGATOR_IMPORTFEEDS, ImportFeeds);
+ CreateServiceFunction(MS_NEWSAGGREGATOR_EXPORTFEEDS, ExportFeeds);
+ CreateServiceFunction(MS_NEWSAGGREGATOR_CHECKFEED, CheckFeed);
+ CreateServiceFunction(MS_NEWSAGGREGATOR_CHANGEFEED, ChangeFeed);
+ CreateServiceFunction(MS_NEWSAGGREGATOR_ENABLED, EnableDisable);
+
+ HOTKEYDESC hkd = {};
+ hkd.dwFlags = HKD_UNICODE;
+ hkd.pszName = "NewsAggregator/CheckAllFeeds";
+ hkd.szDescription.w = LPGENW("Check All Feeds");
+ hkd.szSection.w = LPGENW("News Aggregator");
+ hkd.pszService = MS_NEWSAGGREGATOR_CHECKALLFEEDS;
+ hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL+HKCOMB_A, 'O') | HKF_MIRANDA_LOCAL;
+ g_plugin.addHotkey(&hkd);
+
+ InitIcons();
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Unload()
+{
+ DestroyUpdateList();
+ CloseHandle(hUpdateMutex);
+ return 0;
+}
diff --git a/protocols/NewsAggregator/Src/Options.cpp b/protocols/NewsAggregator/Src/Options.cpp
new file mode 100644
index 0000000000..6239ce15c1
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Options.cpp
@@ -0,0 +1,1016 @@
+/*
+Copyright (C) 2012 Mataes
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include "stdafx.h"
+
+CExportFeed::CExportFeed()
+ : CSuper(g_plugin, IDD_FEEDEXPORT),
+ m_feedslist(this, IDC_FEEDSLIST), m_feedsexportlist(this, IDC_FEEDSEXPORTLIST),
+ m_addfeed(this, IDC_ADDFEED), m_removefeed(this, IDC_REMOVEFEED),
+ m_addallfeeds(this, IDC_ADDALLFEEDS), m_removeallfeeds(this, IDC_REMOVEALLFEEDS),
+ m_ok(this, IDOK)
+{
+ m_addfeed.OnClick = Callback(this, &CExportFeed::OnAddFeed);
+ m_removefeed.OnClick = Callback(this, &CExportFeed::OnRemoveFeed);
+ m_addallfeeds.OnClick = Callback(this, &CExportFeed::OnAddAllFeeds);
+ m_removeallfeeds.OnClick = Callback(this, &CExportFeed::OnRemoveAllFeeds);
+ m_ok.OnClick = Callback(this, &CExportFeed::OnOk);
+
+ m_feedslist.OnDblClick = Callback(this, &CExportFeed::OnFeedsList);
+ m_feedsexportlist.OnDblClick = Callback(this, &CExportFeed::OnFeedsExportList);
+}
+
+bool CExportFeed::OnInitDialog()
+{
+ Utils_RestoreWindowPositionNoSize(m_hwnd, NULL, MODULENAME, "ExportDlg");
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrW message(g_plugin.getWStringA(hContact, "Nick"));
+ if (message != nullptr)
+ m_feedslist.AddString(message);
+ }
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+ if (!m_feedslist.GetCount()) {
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+ }
+ return true;
+}
+
+void CExportFeed::OnAddFeed(CCtrlBase*)
+{
+ if (!m_removefeed.Enabled())
+ m_removefeed.Enable();
+ if (!m_removeallfeeds.Enabled())
+ m_removeallfeeds.Enable();
+ if (!m_ok.Enabled())
+ m_ok.Enable();
+ int cursel = m_feedslist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedslist.GetItemText(cursel, item, _countof(item));
+ m_feedsexportlist.AddString(item);
+ m_feedslist.DeleteString(cursel);
+ if (!m_feedslist.GetCount()) {
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+ }
+}
+
+void CExportFeed::OnRemoveFeed(CCtrlBase*)
+{
+ if (!m_addfeed.Enabled())
+ m_addfeed.Enable();
+ if (!m_addallfeeds.Enabled())
+ m_addallfeeds.Enable();
+ int cursel = m_feedsexportlist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedsexportlist.GetItemText(cursel, item, _countof(item));
+ m_feedslist.AddString(item);
+ m_feedsexportlist.DeleteString(cursel);
+ if (!m_feedsexportlist.GetCount()) {
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+ }
+}
+
+void CExportFeed::OnAddAllFeeds(CCtrlBase*)
+{
+ if (!m_removefeed.Enabled())
+ m_removefeed.Enable();
+ if (!m_removeallfeeds.Enabled())
+ m_removeallfeeds.Enable();
+ if (!m_ok.Enabled())
+ m_ok.Enable();
+ int count = m_feedslist.GetCount();
+ for (int i = 0; i < count; i++) {
+ wchar_t item[MAX_PATH];
+ m_feedslist.GetItemText(i, item, _countof(item));
+ m_feedsexportlist.AddString(item);
+ }
+ for (int i = count - 1; i > -1; i--)
+ m_feedslist.DeleteString(i);
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+}
+
+void CExportFeed::OnRemoveAllFeeds(CCtrlBase*)
+{
+ if (!m_addfeed.Enabled())
+ m_addfeed.Enable();
+ if (!m_addallfeeds.Enabled())
+ m_addallfeeds.Enable();
+ int count = m_feedsexportlist.GetCount();
+ for (int i = 0; i < count; i++) {
+ wchar_t item[MAX_PATH];
+ m_feedsexportlist.GetItemText(i, item, _countof(item));
+ m_feedslist.AddString(item);
+ }
+ for (int i = count - 1; i > -1; i--)
+ m_feedsexportlist.DeleteString(i);
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+}
+
+void CExportFeed::OnFeedsList(CCtrlBase*)
+{
+ if (!m_removefeed.Enabled())
+ m_removefeed.Enable();
+ if (!m_removeallfeeds.Enabled())
+ m_removeallfeeds.Enable();
+ if (!m_ok.Enabled())
+ m_ok.Enable();
+ int cursel = m_feedslist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedslist.GetItemText(cursel, item, _countof(item));
+ m_feedsexportlist.AddString(item);
+ m_feedslist.DeleteString(cursel);
+ if (!m_feedslist.GetCount()) {
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+ }
+}
+
+void CExportFeed::OnFeedsExportList(CCtrlBase*)
+{
+ if (!m_addfeed.Enabled())
+ m_addfeed.Enable();
+ if (!m_addallfeeds.Enabled())
+ m_addallfeeds.Enable();
+ int cursel = m_feedsexportlist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedsexportlist.GetItemText(cursel, item, _countof(item));
+ m_feedslist.AddString(item);
+ m_feedsexportlist.DeleteString(cursel);
+ if (!m_feedsexportlist.GetCount()) {
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+ }
+}
+
+static const TiXmlElement* AdviceNode(const TiXmlElement *node)
+{
+ auto *tmpnode = node;
+
+ // try to rest on the same level first
+ node = node->NextSiblingElement();
+ if (node)
+ return node;
+
+ do {
+ // go up one level
+ node = tmpnode->Parent()->ToElement();
+ tmpnode = node;
+ node = node->NextSiblingElement();
+ if (node)
+ return node;
+ }
+ while (mir_strcmpi(tmpnode->Name(), "body"));
+
+ // nothing found or we reached body
+ return nullptr;
+}
+
+void CExportFeed::OnOk(CCtrlBase*)
+{
+ wchar_t FileName[MAX_PATH];
+ VARSW tszMirDir(L"%miranda_path%");
+
+ OPENFILENAME ofn = { 0 };
+ ofn.lStructSize = sizeof(ofn);
+ wchar_t tmp[MAX_PATH];
+ mir_snwprintf(tmp, L"%s (*.opml)%c*.opml%c%c", TranslateT("OPML files"), 0, 0, 0);
+ ofn.lpstrFilter = tmp;
+ ofn.hwndOwner = nullptr;
+ ofn.lpstrFile = FileName;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.Flags = OFN_HIDEREADONLY | OFN_SHAREAWARE | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
+ ofn.lpstrInitialDir = tszMirDir;
+ *FileName = '\0';
+ ofn.lpstrDefExt = L"";
+ if (!GetSaveFileName(&ofn))
+ return;
+
+ TiXmlDocument doc;
+ auto *hXml = doc.NewElement("opml"); doc.InsertEndChild(hXml);
+ hXml->SetAttribute("version", "1.0");
+
+ auto *xmlHeader = doc.NewElement("head"); hXml->InsertEndChild(xmlHeader);
+ auto *xmlTitle = doc.NewElement("title"); xmlTitle->SetText("Miranda NG NewsAggregator plugin export"); xmlHeader->InsertEndChild(xmlTitle);
+
+ auto *xmlBody = doc.NewElement("body"); hXml->InsertEndChild(xmlBody);
+
+ int count = m_feedsexportlist.GetCount();
+ for (int i = 0; i < count; i++) {
+ wchar_t item[MAX_PATH];
+ m_feedsexportlist.GetItemText(i, item, _countof(item));
+ MCONTACT hContact = GetContactByNick(item);
+ wchar_t
+ *title = g_plugin.getWStringA(hContact, "Nick"),
+ *url = g_plugin.getWStringA(hContact, "URL"),
+ *siteurl = g_plugin.getWStringA(hContact, "Homepage"),
+ *group = db_get_wsa(hContact, "CList", "Group");
+
+ TiXmlElement *elem = xmlBody;
+ if (group) {
+ wchar_t *section = wcstok(group, L"\\");
+ while (section != nullptr) {
+ TiXmlElement *existgroup = 0;
+ for (auto *it : TiXmlFilter(elem, "outline")) {
+ if (it->Attribute("title", T2Utf(section))) {
+ existgroup = (TiXmlElement*)it;
+ break;
+ }
+ }
+
+ if (!existgroup) {
+ auto *pNew = doc.NewElement("outline");
+ pNew->SetAttribute("title", section); pNew->SetAttribute("text", section);
+ elem->InsertEndChild(pNew);
+ elem = pNew;
+ }
+ else elem = existgroup;
+
+ section = wcstok(nullptr, L"\\");
+ }
+ }
+
+ auto *pNew = doc.NewElement("outline"); elem->InsertEndChild(pNew);
+ pNew->SetAttribute("text", title);
+ pNew->SetAttribute("title", title);
+ pNew->SetAttribute("type", "rss");
+ pNew->SetAttribute("xmlUrl", url);
+ pNew->SetAttribute("htmlUrl", siteurl);
+
+ mir_free(title);
+ mir_free(url);
+ mir_free(siteurl);
+ mir_free(group);
+ }
+
+ FILE *out = _wfopen(FileName, L"wb");
+ if (out) {
+ tinyxml2::XMLPrinter printer(out);
+ doc.Print(&printer);
+ fclose(out);
+ }
+}
+
+bool CExportFeed::OnClose()
+{
+ Utils_SaveWindowPosition(m_hwnd, NULL, MODULENAME, "ExportDlg");
+ if (pExportDialog)
+ pExportDialog = nullptr;
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CImportFeed::CImportFeed(CCtrlListView *m_feeds)
+ : CSuper(g_plugin, IDD_FEEDIMPORT),
+ m_importfile(this, IDC_IMPORTFILEPATH), m_browsefile(this, IDC_BROWSEIMPORTFILE),
+ m_feedslist(this, IDC_FEEDSLIST), m_feedsimportlist(this, IDC_FEEDSIMPORTLIST),
+ m_addfeed(this, IDC_ADDFEED), m_removefeed(this, IDC_REMOVEFEED),
+ m_addallfeeds(this, IDC_ADDALLFEEDS), m_removeallfeeds(this, IDC_REMOVEALLFEEDS),
+ m_ok(this, IDOK)
+{
+ m_list = m_feeds;
+ m_browsefile.OnClick = Callback(this, &CImportFeed::OnBrowseFile);
+ m_addfeed.OnClick = Callback(this, &CImportFeed::OnAddFeed);
+ m_removefeed.OnClick = Callback(this, &CImportFeed::OnRemoveFeed);
+ m_addallfeeds.OnClick = Callback(this, &CImportFeed::OnAddAllFeeds);
+ m_removeallfeeds.OnClick = Callback(this, &CImportFeed::OnRemoveAllFeeds);
+ m_ok.OnClick = Callback(this, &CImportFeed::OnOk);
+
+ m_feedslist.OnDblClick = Callback(this, &CImportFeed::OnFeedsList);
+ m_feedsimportlist.OnDblClick = Callback(this, &CImportFeed::OnFeedsImportList);
+}
+
+bool CImportFeed::OnInitDialog()
+{
+ Utils_RestoreWindowPositionNoSize(m_hwnd, NULL, MODULENAME, "ImportDlg");
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+ return true;
+}
+
+void CImportFeed::OnBrowseFile(CCtrlBase*)
+{
+ wchar_t FileName[MAX_PATH];
+ VARSW tszMirDir(L"%miranda_path%");
+
+ OPENFILENAME ofn = { 0 };
+ ofn.lStructSize = sizeof(ofn);
+ wchar_t tmp[MAX_PATH];
+ mir_snwprintf(tmp, L"%s (*.opml, *.xml)%c*.opml;*.xml%c%c", TranslateT("OPML files"), 0, 0, 0);
+ ofn.lpstrFilter = tmp;
+ ofn.hwndOwner = nullptr;
+ ofn.lpstrFile = FileName;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.Flags = OFN_HIDEREADONLY;
+ ofn.lpstrInitialDir = tszMirDir;
+ *FileName = '\0';
+ ofn.lpstrDefExt = L"";
+ if (!GetOpenFileName(&ofn))
+ return;
+
+ FILE *in = _wfopen(FileName, L"rb");
+ if (in == nullptr)
+ return;
+
+ TiXmlDocument doc;
+ int res = doc.LoadFile(in);
+ fclose(in);
+ if (res != 0) {
+ MessageBox(m_hwnd, TranslateT("Not valid import file."), TranslateT("Error"), MB_OK | MB_ICONERROR);
+ return;
+ }
+
+ m_importfile.SetText(FileName);
+
+ auto *node = TiXmlConst(&doc)["opml"]["body"]["outline"].ToElement();
+ if (!node)
+ node = TiXmlConst(&doc)["body"]["outline"].ToElement();
+ if (node == nullptr) {
+ MessageBox(m_hwnd, TranslateT("Not valid import file."), TranslateT("Error"), MB_OK | MB_ICONERROR);
+ return;
+ }
+
+ while (node) {
+ auto *pszUrl = node->Attribute("xmlUrl");
+ if (!pszUrl && node->NoChildren())
+ node = AdviceNode(node);
+ else if (!pszUrl && !node->NoChildren())
+ node = node->FirstChildElement();
+ else if (pszUrl) {
+ if (auto *pszText = node->Attribute("text")) {
+ Utf2T text(pszText);
+ m_feedslist.AddString(text);
+ m_addfeed.Enable();
+ m_addallfeeds.Enable();
+ }
+
+ node = AdviceNode(node);
+ }
+ }
+}
+
+void CImportFeed::OnAddFeed(CCtrlBase*)
+{
+ if (!m_removefeed.Enabled())
+ m_removefeed.Enable();
+ if (!m_removeallfeeds.Enabled())
+ m_removeallfeeds.Enable();
+ if (!m_ok.Enabled())
+ m_ok.Enable();
+ int cursel = m_feedslist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedslist.GetItemText(cursel, item, _countof(item));
+ m_feedsimportlist.AddString(item);
+ m_feedslist.DeleteString(cursel);
+ if (!m_feedslist.GetCount()) {
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+ }
+}
+
+void CImportFeed::OnRemoveFeed(CCtrlBase*)
+{
+ if (!m_addfeed.Enabled())
+ m_addfeed.Enable();
+ if (!m_addallfeeds.Enabled())
+ m_addallfeeds.Enable();
+ int cursel = m_feedsimportlist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedsimportlist.GetItemText(cursel, item, _countof(item));
+ m_feedslist.AddString(item);
+ m_feedsimportlist.DeleteString(cursel);
+ if (!m_feedsimportlist.GetCount()) {
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+ }
+}
+
+void CImportFeed::OnAddAllFeeds(CCtrlBase*)
+{
+ if (!m_removefeed.Enabled())
+ m_removefeed.Enable();
+ if (!m_removeallfeeds.Enabled())
+ m_removeallfeeds.Enable();
+ if (!m_ok.Enabled())
+ m_ok.Enable();
+ int count = m_feedslist.GetCount();
+ for (int i = 0; i < count; i++) {
+ wchar_t item[MAX_PATH];
+ m_feedslist.GetItemText(i, item, _countof(item));
+ m_feedsimportlist.AddString(item);
+ }
+ for (int i = count - 1; i > -1; i--)
+ m_feedslist.DeleteString(i);
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+}
+
+void CImportFeed::OnRemoveAllFeeds(CCtrlBase*)
+{
+ if (!m_addfeed.Enabled())
+ m_addfeed.Enable();
+ if (!m_addallfeeds.Enabled())
+ m_addallfeeds.Enable();
+ int count = m_feedsimportlist.GetCount();
+ for (int i = 0; i < count; i++) {
+ wchar_t item[MAX_PATH];
+ m_feedsimportlist.GetItemText(i, item, _countof(item));
+ m_feedslist.AddString(item);
+ }
+ for (int i = count - 1; i > -1; i--)
+ m_feedsimportlist.DeleteString(i);
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+}
+
+void CImportFeed::OnFeedsList(CCtrlBase*)
+{
+ if (!m_removefeed.Enabled())
+ m_removefeed.Enable();
+ if (!m_removeallfeeds.Enabled())
+ m_removeallfeeds.Enable();
+ if (!m_ok.Enabled())
+ m_ok.Enable();
+ int cursel = m_feedslist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedslist.GetItemText(cursel, item, _countof(item));
+ m_feedsimportlist.AddString(item);
+ m_feedslist.DeleteString(cursel);
+ if (!m_feedslist.GetCount()) {
+ m_addfeed.Disable();
+ m_addallfeeds.Disable();
+ }
+}
+
+void CImportFeed::OnFeedsImportList(CCtrlBase*)
+{
+ if (!m_addfeed.Enabled())
+ m_addfeed.Enable();
+ if (!m_addallfeeds.Enabled())
+ m_addallfeeds.Enable();
+ int cursel = m_feedsimportlist.GetCurSel();
+ wchar_t item[MAX_PATH];
+ m_feedsimportlist.GetItemText(cursel, item, _countof(item));
+ m_feedslist.AddString(item);
+ m_feedsimportlist.DeleteString(cursel);
+ if (!m_feedsimportlist.GetCount()) {
+ m_removefeed.Disable();
+ m_removeallfeeds.Disable();
+ m_ok.Disable();
+ }
+}
+
+void CImportFeed::OnOk(CCtrlBase*)
+{
+ wchar_t FileName[MAX_PATH];
+ m_importfile.GetText(FileName, _countof(FileName));
+
+ FILE *in = _wfopen(FileName, L"rb");
+ if (in == nullptr)
+ return;
+
+ TiXmlDocument doc;
+ int res = doc.LoadFile(in);
+ fclose(in);
+ if (res != 0)
+ return;
+
+ auto *node = TiXmlConst(&doc)["opml"]["body"]["outline"].ToElement();
+ if (!node)
+ node = TiXmlConst(&doc)["body"]["outline"].ToElement();
+ if (node == nullptr)
+ return;
+
+ int count = m_feedsimportlist.GetCount();
+ int DUPES = 0;
+
+ while (node) {
+ auto *pszUrl = node->Attribute("xmlUrl");
+ if (!pszUrl && node->NoChildren())
+ node = AdviceNode(node);
+ else if (!pszUrl && !node->NoChildren())
+ node = node->FirstChildElement();
+ else if (pszUrl) {
+ wchar_t *text = nullptr, *url = nullptr, *siteurl = nullptr;
+ bool bNeedToImport = false;
+
+ if (auto *pszText = node->Attribute("text")) {
+ text = mir_utf8decodeW(pszText);
+
+ for (int j = 0; j < count; j++) {
+ wchar_t item[MAX_PATH];
+ m_feedsimportlist.GetItemText(j, item, _countof(item));
+ if (!mir_wstrcmpi(item, text)) {
+ bNeedToImport = true;
+ break;
+ }
+ }
+ }
+
+ if (auto *pszText = node->Attribute("xmlUrl")) {
+ url = mir_utf8decodeW(pszText);
+ if (GetContactByURL(url) && bNeedToImport) {
+ bNeedToImport = false;
+ DUPES++;
+ }
+ }
+
+ if (auto *pszText = node->Attribute("htmlUrl"))
+ siteurl = mir_utf8decodeW(pszText);
+
+ if (bNeedToImport && text && url && siteurl) {
+ CMStringW wszGroup;
+ auto *parent = node->Parent()->ToElement();
+ while (mir_strcmpi(parent->Name(), "body")) {
+ if (auto *pszText = parent->Attribute("text")) {
+ if (!wszGroup.IsEmpty())
+ wszGroup.Insert(0, L"\\");
+ wszGroup.Insert(0, Utf2T(pszText));
+ }
+ parent = parent->Parent()->ToElement();
+ }
+
+ MCONTACT hContact = db_add_contact();
+ Proto_AddToContact(hContact, MODULENAME);
+ g_plugin.setWString(hContact, "Nick", text);
+ g_plugin.setWString(hContact, "URL", url);
+ g_plugin.setWString(hContact, "Homepage", siteurl);
+ g_plugin.setByte(hContact, "CheckState", 1);
+ g_plugin.setDword(hContact, "UpdateTime", DEFAULT_UPDATE_TIME);
+ g_plugin.setWString(hContact, "MsgFormat", TAGSDEFAULT);
+ g_plugin.setWord(hContact, "Status", Proto_GetStatus(MODULENAME));
+
+ if (m_list != nullptr) {
+ int iItem = m_list->AddItem(text, -1);
+ m_list->SetItem(iItem, 1, url);
+ m_list->SetCheckState(iItem, 1);
+ }
+
+ if (!wszGroup.IsEmpty()) {
+ db_set_ws(hContact, "CList", "Group", wszGroup);
+ Clist_GroupCreate(0, wszGroup);
+ }
+ }
+ mir_free(text);
+ mir_free(url);
+ mir_free(siteurl);
+
+ node = AdviceNode(node);
+ }
+ }
+
+ wchar_t mes[MAX_PATH];
+ if (DUPES)
+ mir_snwprintf(mes, TranslateT("Imported %d feed(s)\r\nNot imported %d duplicate(s)."), count - DUPES, DUPES);
+ else
+ mir_snwprintf(mes, TranslateT("Imported %d feed(s)."), count);
+ MessageBox(m_hwnd, mes, TranslateT("News Aggregator"), MB_OK | MB_ICONINFORMATION);
+}
+
+bool CImportFeed::OnClose()
+{
+ Utils_SaveWindowPosition(m_hwnd, NULL, MODULENAME, "ImportDlg");
+ if (pImportDialog)
+ pImportDialog = nullptr;
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CFeedEditor::CFeedEditor(int iItem, CCtrlListView *m_feeds, MCONTACT Contact)
+ : CSuper(g_plugin, IDD_ADDFEED),
+ m_feedtitle(this, IDC_FEEDTITLE), m_feedurl(this, IDC_FEEDURL),
+ m_checktime(this, IDC_CHECKTIME), m_checktimespin(this, IDC_TIMEOUT_VALUE_SPIN, 999),
+ m_checkfeed(this, IDC_DISCOVERY), m_useauth(this, IDC_USEAUTH),
+ m_login(this, IDC_LOGIN), m_password(this, IDC_PASSWORD),
+ m_tagedit(this, IDC_TAGSEDIT), m_reset(this, IDC_RESET),
+ m_help(this, IDC_TAGHELP), m_ok(this, IDOK), m_iItem(iItem)
+{
+ m_list = m_feeds;
+ m_hContact = Contact;
+ m_checkfeed.OnClick = Callback(this, &CFeedEditor::OnCheckFeed);
+ m_useauth.OnChange = Callback(this, &CFeedEditor::OnUseAuth);
+ m_reset.OnClick = Callback(this, &CFeedEditor::OnReset);
+ m_help.OnClick = Callback(this, &CFeedEditor::OnHelp);
+ m_ok.OnClick = Callback(this, &CFeedEditor::OnOk);
+}
+
+bool CFeedEditor::OnInitDialog()
+{
+ if (m_iItem == -1 && m_hContact == NULL)
+ SetWindowText(m_hwnd, TranslateT("Add Feed"));
+ else
+ SetWindowText(m_hwnd, TranslateT("Change Feed"));
+ m_checktime.SetMaxLength(3);
+
+ if (m_iItem > -1 && m_hContact == 0) {
+ wchar_t SelNick[MAX_PATH], SelUrl[MAX_PACKAGE_NAME];
+ m_list->GetItemText(m_iItem, 0, SelNick, _countof(SelNick));
+ m_list->GetItemText(m_iItem, 1, SelUrl, _countof(SelNick));
+
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrW dbNick(g_plugin.getWStringA(hContact, "Nick"));
+ if ((dbNick == NULL) || (mir_wstrcmp(dbNick, SelNick) != 0))
+ continue;
+
+ ptrW dbURL(g_plugin.getWStringA(hContact, "URL"));
+ if ((dbURL == NULL) || (mir_wstrcmp(dbURL, SelUrl) != 0))
+ continue;
+
+ m_hContact = hContact;
+ m_feedtitle.SetText(SelNick);
+ m_feedurl.SetText(SelUrl);
+ m_checktime.SetInt(g_plugin.getDword(hContact, "UpdateTime", DEFAULT_UPDATE_TIME));
+
+ ptrW szMsgFormat(g_plugin.getWStringA(hContact, "MsgFormat"));
+ if (szMsgFormat)
+ m_tagedit.SetText(szMsgFormat);
+
+ if (g_plugin.getByte(hContact, "UseAuth", 0)) {
+ m_useauth.SetState(1);
+ m_login.Enable();
+ m_password.Enable();
+
+ ptrW szLogin(g_plugin.getWStringA(hContact, "Login"));
+ if (szLogin)
+ m_login.SetText(szLogin);
+
+ pass_ptrA pwd(g_plugin.getStringA(hContact, "Password"));
+ m_password.SetTextA(pwd);
+ }
+ g_arFeeds.insert(this);
+ Utils_RestoreWindowPositionNoSize(m_hwnd, hContact, MODULENAME, "ChangeDlg");
+ break;
+ }
+ }
+ else if (m_iItem == -1 && m_hContact == NULL) {
+ m_feedurl.SetText(L"http://");
+ m_tagedit.SetText(TAGSDEFAULT);
+ m_checktime.SetInt(DEFAULT_UPDATE_TIME);
+ Utils_RestoreWindowPositionNoSize(m_hwnd, NULL, MODULENAME, "AddDlg");
+ }
+ else if (m_hContact != NULL) {
+ ptrW dbNick(g_plugin.getWStringA(m_hContact, "Nick"));
+ ptrW dbURL(g_plugin.getWStringA(m_hContact, "URL"));
+
+ m_feedtitle.SetText(dbNick);
+ m_feedurl.SetText(dbURL);
+ m_checktime.SetInt(g_plugin.getDword(m_hContact, "UpdateTime", DEFAULT_UPDATE_TIME));
+
+ ptrW szMsgFormat(g_plugin.getWStringA(m_hContact, "MsgFormat"));
+ if (szMsgFormat)
+ m_tagedit.SetText(szMsgFormat);
+
+ if (g_plugin.getByte(m_hContact, "UseAuth")) {
+ m_useauth.SetState(1);
+ m_login.Enable();
+ m_password.Enable();
+
+ ptrW szLogin(g_plugin.getWStringA(m_hContact, "Login"));
+ if (szLogin)
+ m_login.SetText(szLogin);
+
+ pass_ptrA pwd(g_plugin.getStringA(m_hContact, "Password"));
+ m_password.SetTextA(pwd);
+ }
+ g_arFeeds.insert(this);
+ Utils_RestoreWindowPositionNoSize(m_hwnd, m_hContact, MODULENAME, "ChangeDlg");
+ }
+ return true;
+}
+
+void CFeedEditor::OnCheckFeed(CCtrlBase*)
+{
+ m_checkfeed.Disable();
+ m_checkfeed.SetText(TranslateT("Wait..."));
+ wchar_t *tszTitle = nullptr;
+ ptrW strfeedurl(m_feedurl.GetText());
+ if (strfeedurl || mir_wstrcmp(strfeedurl, L"http://") != 0 || mir_wstrcmp(strfeedurl, L"") != 0)
+ tszTitle = (wchar_t*)CheckFeed(strfeedurl, this);
+ else
+ MessageBox(m_hwnd, TranslateT("Enter Feed URL"), TranslateT("Error"), MB_OK);
+ m_feedtitle.SetText(tszTitle);
+ mir_free(tszTitle);
+ m_checkfeed.Enable();
+ m_checkfeed.SetText(TranslateT("Check Feed"));
+}
+
+void CFeedEditor::OnReset(CCtrlBase*)
+{
+ if (MessageBox(m_hwnd, TranslateT("Are you sure?"), TranslateT("Tags Mask Reset"), MB_YESNO | MB_ICONWARNING) == IDYES)
+ m_tagedit.SetText(TAGSDEFAULT);
+}
+
+void CFeedEditor::OnHelp(CCtrlBase*)
+{
+ CMStringW wszTagHelp;
+ wszTagHelp.Format(L"%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s\n%s - %s",
+ L"#<title>#", TranslateT("The title of the item."),
+ L"#<description>#", TranslateT("The item synopsis."),
+ L"#<link>#", TranslateT("The URL of the item."),
+ L"#<author>#", TranslateT("Email address of the author of the item."),
+ L"#<comments>#", TranslateT("URL of a page for comments relating to the item."),
+ L"#<guid>#", TranslateT("A string that uniquely identifies the item."),
+ L"#<category>#", TranslateT("Specify one or more categories that the item belongs to."));
+ MessageBox(m_hwnd, wszTagHelp, TranslateT("Feed Tag Help"), MB_OK);
+}
+
+void CFeedEditor::OnOk(CCtrlBase*)
+{
+ ptrW strfeedtitle(m_feedtitle.GetText());
+ if (!strfeedtitle || mir_wstrcmp(strfeedtitle, L"") == 0) {
+ MessageBox(m_hwnd, TranslateT("Enter Feed name"), TranslateT("Error"), MB_OK);
+ return;
+ }
+
+ ptrW strfeedurl(m_feedurl.GetText());
+ if (!strfeedurl || mir_wstrcmp(strfeedurl, L"http://") == 0 || mir_wstrcmp(strfeedurl, L"") == 0) {
+ MessageBox(m_hwnd, TranslateT("Enter Feed URL"), TranslateT("Error"), MB_OK);
+ return;
+ }
+
+ ptrW strtagedit(m_tagedit.GetText());
+ if (!strtagedit || mir_wstrcmp(strtagedit, L"") == 0) {
+ MessageBox(m_hwnd, TranslateT("Enter message format"), TranslateT("Error"), MB_OK);
+ return;
+ }
+
+ MCONTACT hContact;
+ if (m_iItem == -1 && m_hContact == NULL) {
+ hContact = db_add_contact();
+ Proto_AddToContact(hContact, MODULENAME);
+ g_plugin.setByte(hContact, "CheckState", 1);
+ }
+ else hContact = m_hContact;
+
+ g_plugin.setWString(hContact, "Nick", strfeedtitle);
+ g_plugin.setWString(hContact, "URL", strfeedurl);
+ g_plugin.setDword(hContact, "UpdateTime", m_checktime.GetInt());
+ g_plugin.setWString(hContact, "MsgFormat", strtagedit);
+ g_plugin.setWord(hContact, "Status", Proto_GetStatus(MODULENAME));
+ if (m_useauth.IsChecked()) {
+ g_plugin.setByte(hContact, "UseAuth", 1);
+ g_plugin.setWString(hContact, "Login", m_login.GetText());
+ g_plugin.setString(hContact, "Password", m_password.GetTextA());
+ }
+ else {
+ g_plugin.delSetting(hContact, "UseAuth");
+ g_plugin.delSetting(hContact, "Login");
+ g_plugin.delSetting(hContact, "Password");
+ }
+
+ if (m_iItem == -1 && m_list != nullptr && m_hContact == NULL) {
+ int iItem = m_list->AddItem(strfeedtitle, -1);
+ m_list->SetItem(iItem, 1, strfeedurl);
+ m_list->SetCheckState(iItem, 1);
+ }
+ else if (m_iItem > -1) {
+ m_list->SetItem(m_iItem, 0, strfeedtitle);
+ m_list->SetItem(m_iItem, 1, strfeedurl);
+ }
+}
+
+bool CFeedEditor::OnClose()
+{
+ g_arFeeds.remove(this);
+ Utils_SaveWindowPosition(m_hwnd, NULL, MODULENAME, m_iItem == -1 ? "AddDlg" : "ChangeDlg");
+ if (pAddFeedDialog == this)
+ pAddFeedDialog = nullptr;
+ return true;
+}
+
+void CFeedEditor::OnUseAuth(CCtrlBase*)
+{
+ m_login.Enable(m_useauth.GetState());
+ m_password.Enable(m_useauth.GetState());
+}
+
+void COptionsMain::UpdateList()
+{
+ for (auto &hContact : Contacts(MODULENAME)) {
+ UpdateListFlag = TRUE;
+ ptrW ptszNick(g_plugin.getWStringA(hContact, "Nick"));
+ if (ptszNick) {
+ int iItem = m_feeds.AddItem(ptszNick, -1);
+
+ ptrW ptszURL(g_plugin.getWStringA(hContact, "URL"));
+ if (ptszURL) {
+ m_feeds.SetItem(iItem, 1, ptszURL);
+ m_feeds.SetCheckState(iItem, g_plugin.getByte(hContact, "CheckState", 1));
+ }
+ }
+ }
+ UpdateListFlag = FALSE;
+}
+
+COptionsMain::COptionsMain() :
+ CDlgBase(g_plugin, IDD_OPTIONS),
+ m_feeds(this, IDC_FEEDLIST),
+ m_add(this, IDC_ADD),
+ m_change(this, IDC_CHANGE),
+ m_delete(this, IDC_REMOVE),
+ m_import(this, IDC_IMPORT),
+ m_export(this, IDC_EXPORT),
+ m_checkonstartup(this, IDC_STARTUPRETRIEVE)
+{
+ CreateLink(m_checkonstartup, "StartupRetrieve", DBVT_BYTE, 1);
+
+ m_add.OnClick = Callback(this, &COptionsMain::OnAddButtonClick);
+ m_change.OnClick = Callback(this, &COptionsMain::OnChangeButtonClick);
+ m_delete.OnClick = Callback(this, &COptionsMain::OnDeleteButtonClick);
+ m_import.OnClick = Callback(this, &COptionsMain::OnImportButtonClick);
+ m_export.OnClick = Callback(this, &COptionsMain::OnExportButtonClick);
+
+ m_feeds.OnItemChanged = Callback(this, &COptionsMain::OnFeedListItemChanged);
+ m_feeds.OnDoubleClick = Callback(this, &COptionsMain::OnFeedListDoubleClick);
+
+}
+
+bool COptionsMain::OnInitDialog()
+{
+ CDlgBase::OnInitDialog();
+ m_change.Disable();
+ m_delete.Disable();
+ m_feeds.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
+ m_feeds.AddColumn(0, TranslateT("Feed"), 160);
+ m_feeds.AddColumn(1, TranslateT("URL"), 276);
+ UpdateList();
+ return true;
+}
+
+bool COptionsMain::OnApply()
+{
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrW dbNick(g_plugin.getWStringA(hContact, "Nick"));
+ for (int i = 0; i < m_feeds.GetItemCount(); i++) {
+ wchar_t nick[MAX_PATH];
+ m_feeds.GetItemText(i, 0, nick, _countof(nick));
+ if (mir_wstrcmp(dbNick, nick) == 0) {
+ g_plugin.setByte(hContact, "CheckState", m_feeds.GetCheckState(i));
+ if (!m_feeds.GetCheckState(i))
+ db_set_b(hContact, "CList", "Hidden", 1);
+ else
+ db_unset(hContact, "CList", "Hidden");
+ }
+ }
+ }
+ return true;
+}
+
+void COptionsMain::OnAddButtonClick(CCtrlBase*)
+{
+ if (pAddFeedDialog == nullptr) {
+ pAddFeedDialog = new CFeedEditor(-1, &m_feeds, NULL);
+ pAddFeedDialog->SetParent(m_hwnd);
+ pAddFeedDialog->Show();
+ }
+ else {
+ SetForegroundWindow(pAddFeedDialog->GetHwnd());
+ SetFocus(pAddFeedDialog->GetHwnd());
+ }
+}
+
+void COptionsMain::OnChangeButtonClick(CCtrlBase*)
+{
+ int isel = m_feeds.GetSelectionMark();
+ CFeedEditor *pDlg = nullptr;
+ for (auto &it : g_arFeeds) {
+ wchar_t nick[MAX_PATH], url[MAX_PATH];
+ m_feeds.GetItemText(isel, 0, nick, _countof(nick));
+ m_feeds.GetItemText(isel, 1, url, _countof(url));
+
+ ptrW dbNick(g_plugin.getWStringA(it->getContact(), "Nick"));
+ if ((dbNick == NULL) || (mir_wstrcmp(dbNick, nick) != 0))
+ continue;
+
+ ptrW dbURL(g_plugin.getWStringA(it->getContact(), "URL"));
+ if ((dbURL == NULL) || (mir_wstrcmp(dbURL, url) != 0))
+ continue;
+
+ pDlg = it;
+ }
+
+ if (pDlg == nullptr) {
+ pDlg = new CFeedEditor(isel, &m_feeds, NULL);
+ pDlg->SetParent(m_hwnd);
+ pDlg->Show();
+ }
+ else {
+ SetForegroundWindow(pDlg->GetHwnd());
+ SetFocus(pDlg->GetHwnd());
+ }
+}
+
+void COptionsMain::OnDeleteButtonClick(CCtrlBase*)
+{
+ if (MessageBox(m_hwnd, TranslateT("Are you sure?"), TranslateT("Contact deleting"), MB_YESNO | MB_ICONWARNING) == IDYES) {
+ wchar_t nick[MAX_PATH], url[MAX_PATH];
+ int isel = m_feeds.GetSelectionMark();
+ m_feeds.GetItemText(isel, 0, nick, _countof(nick));
+ m_feeds.GetItemText(isel, 1, url, _countof(url));
+
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrW dbNick(g_plugin.getWStringA(hContact, "Nick"));
+ if (dbNick == NULL)
+ break;
+ if (mir_wstrcmp(dbNick, nick))
+ continue;
+
+ ptrW dbURL(g_plugin.getWStringA(hContact, "URL"));
+ if (dbURL == NULL)
+ break;
+ if (mir_wstrcmp(dbURL, url))
+ continue;
+
+ db_delete_contact(hContact);
+ m_feeds.DeleteItem(isel);
+ break;
+ }
+ }
+}
+
+void COptionsMain::OnImportButtonClick(CCtrlBase*)
+{
+ if (pImportDialog == nullptr) {
+ pImportDialog = new CImportFeed(&m_feeds);
+ pImportDialog->Show();
+ pImportDialog->SetParent(m_hwnd);
+ }
+}
+
+void COptionsMain::OnExportButtonClick(CCtrlBase*)
+{
+ if (pExportDialog == nullptr) {
+ pExportDialog = new CExportFeed();
+ pExportDialog->Show();
+ pExportDialog->SetParent(m_hwnd);
+ }
+}
+
+void COptionsMain::OnFeedListItemChanged(CCtrlListView::TEventInfo *evt)
+{
+ int isel = m_feeds.GetSelectionMark();
+ if (isel == -1) {
+ m_change.Disable();
+ m_delete.Disable();
+ }
+ else {
+ m_change.Enable();
+ m_delete.Enable();
+ }
+ if (((evt->nmlv->uNewState ^ evt->nmlv->uOldState) & LVIS_STATEIMAGEMASK) && !UpdateListFlag)
+ NotifyChange();
+}
+
+void COptionsMain::OnFeedListDoubleClick(CCtrlBase*)
+{
+ int isel = m_feeds.GetHotItem();
+ if (isel != -1) {
+ CFeedEditor *pDlg = new CFeedEditor(isel, &m_feeds, 0);
+ pDlg->SetParent(m_hwnd);
+ pDlg->Show();
+ }
+}
+
+int OptInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE;
+ odp.szGroup.w = LPGENW("Network");
+ odp.szTitle.w = LPGENW("News Aggregator");
+ odp.pDialog = new COptionsMain();
+ g_plugin.addOptions(wParam, &odp);
+ return 0;
+}
diff --git a/protocols/NewsAggregator/Src/Options.h b/protocols/NewsAggregator/Src/Options.h
new file mode 100644
index 0000000000..2389eb9bb9
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Options.h
@@ -0,0 +1,162 @@
+#ifndef _OPTIONS_H_
+#define _OPTIONS_H_
+
+class COptionsMain : public CDlgBase
+{
+private:
+ CCtrlListView m_feeds;
+ CCtrlButton m_add;
+ CCtrlButton m_change;
+ CCtrlButton m_delete;
+ CCtrlButton m_import;
+ CCtrlButton m_export;
+ CCtrlCheck m_checkonstartup;
+
+protected:
+ bool OnInitDialog() override;
+ bool OnApply() override;
+
+ void OnAddButtonClick(CCtrlBase*);
+ void OnChangeButtonClick(CCtrlBase*);
+ void OnDeleteButtonClick(CCtrlBase*);
+ void OnImportButtonClick(CCtrlBase*);
+ void OnExportButtonClick(CCtrlBase*);
+
+ void OnFeedListItemChanged(CCtrlListView::TEventInfo *evt);
+ void OnFeedListDoubleClick(CCtrlBase*);
+
+ void UpdateList();
+
+public:
+ COptionsMain();
+};
+
+class CFeedEditor : public CDlgBase
+{
+ friend class CAuthRequest;
+
+private:
+ typedef CDlgBase CSuper;
+
+ int m_iItem;
+ CCtrlListView *m_list;
+ MCONTACT m_hContact;
+
+ CCtrlEdit m_feedtitle;
+ CCtrlEdit m_feedurl;
+ CCtrlEdit m_checktime;
+ CCtrlSpin m_checktimespin;
+ CCtrlButton m_checkfeed;
+ CCtrlEdit m_tagedit;
+ CCtrlButton m_reset;
+ CCtrlButton m_help;
+ CCtrlButton m_ok;
+
+protected:
+ bool OnInitDialog() override;
+ bool OnClose() override;
+
+ void OnCheckFeed(CCtrlBase*);
+ void OnReset(CCtrlBase*);
+ void OnHelp(CCtrlBase*);
+ void OnOk(CCtrlBase*);
+ void OnUseAuth(CCtrlBase*);
+
+public:
+ CCtrlCheck m_useauth;
+ CCtrlEdit m_login;
+ CCtrlEdit m_password;
+
+ CFeedEditor(int iItem, CCtrlListView *m_list, MCONTACT Contact);
+
+ __inline MCONTACT getContact() const { return m_hContact; }
+};
+
+class CImportFeed : public CDlgBase
+{
+private:
+ typedef CDlgBase CSuper;
+
+ CCtrlListView *m_list;
+
+ CCtrlEdit m_importfile;
+ CCtrlButton m_browsefile;
+ CCtrlListBox m_feedslist;
+ CCtrlListBox m_feedsimportlist;
+ CCtrlButton m_addfeed;
+ CCtrlButton m_removefeed;
+ CCtrlButton m_addallfeeds;
+ CCtrlButton m_removeallfeeds;
+ CCtrlButton m_ok;
+
+protected:
+ bool OnInitDialog() override;
+ bool OnClose() override;
+
+ void OnBrowseFile(CCtrlBase*);
+ void OnAddFeed(CCtrlBase*);
+ void OnRemoveFeed(CCtrlBase*);
+ void OnAddAllFeeds(CCtrlBase*);
+ void OnRemoveAllFeeds(CCtrlBase*);
+ void OnOk(CCtrlBase*);
+
+ void OnFeedsList(CCtrlBase*);
+ void OnFeedsImportList(CCtrlBase*);
+
+public:
+ CImportFeed(CCtrlListView *m_list);
+};
+
+class CExportFeed : public CDlgBase
+{
+private:
+ typedef CDlgBase CSuper;
+
+ CCtrlListBox m_feedslist;
+ CCtrlListBox m_feedsexportlist;
+ CCtrlButton m_addfeed;
+ CCtrlButton m_removefeed;
+ CCtrlButton m_addallfeeds;
+ CCtrlButton m_removeallfeeds;
+ CCtrlButton m_ok;
+
+protected:
+ bool OnInitDialog() override;
+ bool OnClose() override;
+
+ void OnAddFeed(CCtrlBase*);
+ void OnRemoveFeed(CCtrlBase*);
+ void OnAddAllFeeds(CCtrlBase*);
+ void OnRemoveAllFeeds(CCtrlBase*);
+ void OnOk(CCtrlBase*);
+
+ void OnFeedsList(CCtrlBase*);
+ void OnFeedsExportList(CCtrlBase*);
+
+public:
+ CExportFeed();
+};
+
+class CAuthRequest : public CDlgBase
+{
+private:
+ typedef CDlgBase CSuper;
+
+ CFeedEditor *m_pDlg;
+ MCONTACT m_hContact;
+
+ CCtrlBase m_feedname;
+ CCtrlEdit m_username;
+ CCtrlEdit m_password;
+ CCtrlButton m_ok;
+
+protected:
+ bool OnInitDialog() override;
+
+ void OnOk(CCtrlBase*);
+
+public:
+ CAuthRequest(CFeedEditor *pDlg, MCONTACT hContact);
+};
+
+#endif //_OPTIONS_H_ \ No newline at end of file
diff --git a/protocols/NewsAggregator/Src/Services.cpp b/protocols/NewsAggregator/Src/Services.cpp
new file mode 100644
index 0000000000..b5b8c9f028
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Services.cpp
@@ -0,0 +1,261 @@
+/*
+Copyright (C) 2012 Mataes
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include "stdafx.h"
+
+int g_nStatus = ID_STATUS_ONLINE;
+UINT_PTR timerId = 0;
+HANDLE hTBButton = nullptr, hNewsAggregatorFolder = nullptr;
+
+int OnFoldersChanged(WPARAM, LPARAM)
+{
+ FoldersGetCustomPathT(hNewsAggregatorFolder, tszRoot, MAX_PATH, L"");
+ return 0;
+}
+
+int NewsAggrInit(WPARAM, LPARAM)
+{
+ if (hNewsAggregatorFolder = FoldersRegisterCustomPathT(LPGEN("Avatars"), LPGEN("News Aggregator"), MIRANDA_USERDATAT L"\\Avatars\\" _A2W(DEFAULT_AVATARS_FOLDER)))
+ FoldersGetCustomPathT(hNewsAggregatorFolder, tszRoot, MAX_PATH, L"");
+ else
+ mir_wstrncpy(tszRoot, VARSW(L"%miranda_userdata%\\Avatars\\" _A2W(DEFAULT_AVATARS_FOLDER)), _countof(tszRoot));
+
+ for (auto &hContact : Contacts(MODULENAME)) {
+ if (!g_plugin.getByte("StartupRetrieve", 1))
+ g_plugin.setDword(hContact, "LastCheck", (DWORD)time(0));
+ g_plugin.setWord(hContact, "Status", ID_STATUS_ONLINE);
+ }
+
+ NetlibInit();
+ InitMenu();
+
+ HookEvent(ME_TTB_MODULELOADED, OnToolbarLoaded);
+ HookEvent(ME_FOLDERS_PATH_CHANGED, OnFoldersChanged);
+
+ // timer for the first update
+ timerId = SetTimer(nullptr, 0, 10000, timerProc2); // first update is 10 sec after load
+
+ return 0;
+}
+
+int NewsAggrPreShutdown(WPARAM, LPARAM)
+{
+ KillTimer(nullptr, timerId);
+ NetlibUnInit();
+ return 0;
+}
+
+INT_PTR NewsAggrGetName(WPARAM wParam, LPARAM lParam)
+{
+ if(lParam) {
+ mir_strncpy((char *)lParam, MODULENAME, wParam);
+ return 0;
+ }
+
+ return 1;
+}
+
+INT_PTR NewsAggrGetCaps(WPARAM wp, LPARAM)
+{
+ switch(wp) {
+ case PFLAGNUM_1:
+ return PF1_IM | PF1_PEER2PEER;
+ case PFLAGNUM_3:
+ case PFLAGNUM_2:
+ return PF2_ONLINE;
+ case PFLAGNUM_4:
+ return PF4_AVATARS;
+ case PFLAG_UNIQUEIDTEXT:
+ return (INT_PTR) "News Feed";
+ default:
+ return 0;
+ }
+}
+
+INT_PTR NewsAggrSetStatus(WPARAM wp, LPARAM)
+{
+ int nStatus = (int)wp;
+ if ((ID_STATUS_ONLINE == nStatus) || (ID_STATUS_OFFLINE == nStatus)) {
+ int nOldStatus = g_nStatus;
+ if(nStatus != g_nStatus) {
+ g_nStatus = nStatus;
+
+ for (auto &hContact : Contacts(MODULENAME))
+ g_plugin.setWord(hContact, "Status", nStatus);
+
+ ProtoBroadcastAck(MODULENAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)nOldStatus, (LPARAM)g_nStatus);
+ }
+ }
+
+ return 0;
+}
+
+INT_PTR NewsAggrGetStatus(WPARAM, LPARAM)
+{
+ return g_nStatus;
+}
+
+INT_PTR NewsAggrLoadIcon(WPARAM wParam, LPARAM)
+{
+ return (LOWORD(wParam) == PLI_PROTOCOL) ? (INT_PTR)CopyIcon(LoadIconEx("main", FALSE)) : 0;
+}
+
+static void __cdecl AckThreadProc(void *param)
+{
+ Sleep(100);
+ ProtoBroadcastAck(MODULENAME, (MCONTACT)param, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, (HANDLE)1);
+}
+
+INT_PTR NewsAggrGetInfo(WPARAM, LPARAM lParam)
+{
+ CCSDATA *ccs = (CCSDATA *)lParam;
+ mir_forkthread(AckThreadProc, (void*)ccs->hContact);
+ return 0;
+}
+
+INT_PTR CheckAllFeeds(WPARAM, LPARAM lParam)
+{
+ for (auto &hContact : Contacts(MODULENAME)) {
+ if (lParam && g_plugin.getDword(hContact, "UpdateTime", DEFAULT_UPDATE_TIME))
+ UpdateListAdd(hContact);
+ else if (!lParam)
+ UpdateListAdd(hContact);
+ }
+ if (!ThreadRunning)
+ mir_forkthread(UpdateThreadProc);
+
+ return 0;
+}
+
+INT_PTR AddFeed(WPARAM, LPARAM)
+{
+ if (pAddFeedDialog == nullptr) {
+ pAddFeedDialog = new CFeedEditor(-1, nullptr, NULL);
+ pAddFeedDialog->Show();
+ }
+ else {
+ SetForegroundWindow(pAddFeedDialog->GetHwnd());
+ SetFocus(pAddFeedDialog->GetHwnd());
+ }
+ return 0;
+}
+
+INT_PTR ChangeFeed(WPARAM hContact, LPARAM)
+{
+ CFeedEditor *pDlg = nullptr;
+ for (auto &it : g_arFeeds)
+ if (it->getContact() == hContact)
+ pDlg = it;
+
+ if (pDlg == nullptr) {
+ pDlg = new CFeedEditor(-1, nullptr, (MCONTACT)hContact);
+ pDlg->Show();
+ }
+ else {
+ SetForegroundWindow(pDlg->GetHwnd());
+ SetFocus(pDlg->GetHwnd());
+ }
+ return 0;
+}
+
+INT_PTR ImportFeeds(WPARAM, LPARAM)
+{
+ if (pImportDialog == nullptr)
+ pImportDialog = new CImportFeed(nullptr);
+ pImportDialog->Show();
+ return 0;
+}
+
+INT_PTR ExportFeeds(WPARAM, LPARAM)
+{
+ if (pExportDialog == nullptr)
+ pExportDialog = new CExportFeed();
+ pExportDialog->Show();
+ return 0;
+}
+
+INT_PTR CheckFeed(WPARAM hContact, LPARAM)
+{
+ if(IsMyContact((MCONTACT)hContact))
+ UpdateListAdd((MCONTACT)hContact);
+ if ( !ThreadRunning)
+ mir_forkthread(UpdateThreadProc);
+ return 0;
+}
+
+INT_PTR NewsAggrGetAvatarInfo(WPARAM wParam, LPARAM lParam)
+{
+ PROTO_AVATAR_INFORMATION *pai = (PROTO_AVATAR_INFORMATION *)lParam;
+ if (!IsMyContact(pai->hContact))
+ return GAIR_NOAVATAR;
+
+ // if GAIF_FORCE is set, we are updating the feed
+ // otherwise, cached avatar is used
+ if ((wParam & GAIF_FORCE) && g_plugin.getDword(pai->hContact, "UpdateTime", DEFAULT_UPDATE_TIME))
+ UpdateListAdd(pai->hContact);
+ if (g_plugin.getByte("AutoUpdate", 1) != 0 && !ThreadRunning)
+ mir_forkthread(UpdateThreadProc, (void *)TRUE);
+
+ ptrW ptszImageURL(g_plugin.getWStringA(pai->hContact, "ImageURL"));
+ return (ptszImageURL == nullptr) ? GAIR_NOAVATAR : GAIR_WAITFOR;
+}
+
+INT_PTR NewsAggrRecvMessage(WPARAM, LPARAM lParam)
+{
+ PROTOACCOUNT *pa = Proto_GetAccount(MODULENAME);
+ if (pa && pa->ppro) {
+ CCSDATA *ccs = (CCSDATA*)lParam;
+ pa->ppro->PROTO_INTERFACE::RecvMsg(ccs->hContact, (PROTORECVEVENT*)ccs->lParam);
+ }
+
+ return 0;
+}
+
+void UpdateMenu(bool State)
+{
+ if (!State) // to enable auto-update
+ Menu_ModifyItem(hService2[0], LPGENW("Auto Update Enabled"), GetIconHandle("enabled"));
+ else // to disable auto-update
+ Menu_ModifyItem(hService2[0], LPGENW("Auto Update Disabled"), GetIconHandle("disabled"));
+
+ CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)hTBButton, State ? TTBST_PUSHED : 0);
+ g_plugin.setByte("AutoUpdate", !State);
+}
+
+// update the newsaggregator auto-update menu item when click on it
+INT_PTR EnableDisable(WPARAM, LPARAM)
+{
+ UpdateMenu(g_plugin.getByte("AutoUpdate", 1) != 0);
+ NewsAggrSetStatus(g_plugin.getByte("AutoUpdate", 1) ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE, 0);
+ return 0;
+}
+
+int OnToolbarLoaded(WPARAM, LPARAM)
+{
+ TTBButton ttb = {};
+ ttb.name = LPGEN("Enable/disable auto update");
+ ttb.pszService = MS_NEWSAGGREGATOR_ENABLED;
+ ttb.pszTooltipUp = LPGEN("Auto Update Enabled");
+ ttb.pszTooltipDn = LPGEN("Auto Update Disabled");
+ ttb.hIconHandleUp = GetIconHandle("enabled");
+ ttb.hIconHandleDn = GetIconHandle("disabled");
+ ttb.dwFlags = (g_plugin.getByte("AutoUpdate", 1) ? 0 : TTBBF_PUSHED) | TTBBF_ASPUSHBUTTON | TTBBF_VISIBLE;
+ hTBButton = g_plugin.addTTB(&ttb);
+ return 0;
+}
diff --git a/protocols/NewsAggregator/Src/Update.cpp b/protocols/NewsAggregator/Src/Update.cpp
new file mode 100644
index 0000000000..96990dbcd2
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Update.cpp
@@ -0,0 +1,139 @@
+/*
+Copyright (C) 2012 Mataes
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include "stdafx.h"
+
+// check if Feed is currently updating
+bool ThreadRunning;
+UPDATELIST *UpdateListHead = nullptr;
+UPDATELIST *UpdateListTail = nullptr;
+
+// main auto-update timer
+void CALLBACK timerProc(HWND, UINT, UINT_PTR, DWORD)
+{
+ // only run if it is not current updating and the auto update option is enabled
+ if (!ThreadRunning && !Miranda_IsTerminated()) {
+ bool HaveUpdates = FALSE;
+ for (auto &hContact : Contacts(MODULENAME)) {
+ if (g_plugin.getDword(hContact, "UpdateTime", DEFAULT_UPDATE_TIME)) {
+ double diff = difftime(time(0), (time_t)g_plugin.getDword(hContact, "LastCheck", 0));
+ if (g_plugin.getByte("AutoUpdate", 1) != 0 && diff >= g_plugin.getDword(hContact, "UpdateTime", DEFAULT_UPDATE_TIME) * 60) {
+ UpdateListAdd(hContact);
+ HaveUpdates = TRUE;
+ }
+ }
+ }
+ if (!ThreadRunning && HaveUpdates)
+ mir_forkthread(UpdateThreadProc);
+ }
+}
+
+// temporary timer for first run
+// when this is run, it kill the old startup timer and create the permenant one above
+void CALLBACK timerProc2(HWND, UINT, UINT_PTR, DWORD)
+{
+ KillTimer(nullptr, timerId);
+ ThreadRunning = FALSE;
+
+ if (g_plugin.getByte("AutoUpdate", 1) && !Miranda_IsTerminated()) {
+ if (g_plugin.getByte("StartupRetrieve", 1))
+ CheckAllFeeds(0, 1);
+ timerId = SetTimer(nullptr, 0, 30000, (TIMERPROC)timerProc);
+ }
+}
+
+void UpdateListAdd(MCONTACT hContact)
+{
+ UPDATELIST *newItem = (UPDATELIST*)mir_alloc(sizeof(UPDATELIST));
+ newItem->hContact = hContact;
+ newItem->next = nullptr;
+
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+
+ if (UpdateListTail == nullptr)
+ UpdateListHead = newItem;
+ else UpdateListTail->next = newItem;
+ UpdateListTail = newItem;
+
+ ReleaseMutex(hUpdateMutex);
+}
+
+MCONTACT UpdateGetFirst()
+{
+ MCONTACT hContact = NULL;
+
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+
+ if (UpdateListHead != nullptr) {
+ UPDATELIST* Item = UpdateListHead;
+ hContact = Item->hContact;
+ UpdateListHead = Item->next;
+ mir_free(Item);
+
+ if (UpdateListHead == nullptr)
+ UpdateListTail = nullptr;
+ }
+
+ ReleaseMutex(hUpdateMutex);
+
+ return hContact;
+}
+
+void DestroyUpdateList(void)
+{
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+
+ // free the list one by one
+ UPDATELIST *temp = UpdateListHead;
+ while (temp != nullptr) {
+ UpdateListHead = temp->next;
+ mir_free(temp);
+ temp = UpdateListHead;
+ }
+ // make sure the entire list is clear
+ UpdateListTail = nullptr;
+
+ ReleaseMutex(hUpdateMutex);
+}
+
+void UpdateThreadProc(void *AvatarCheck)
+{
+ WaitForSingleObject(hUpdateMutex, INFINITE);
+ if (ThreadRunning) {
+ ReleaseMutex(hUpdateMutex);
+ return;
+ }
+ ThreadRunning = TRUE; // prevent 2 instance of this thread running
+ ReleaseMutex(hUpdateMutex);
+
+ CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
+
+ // update news by getting the first station from the queue until the queue is empty
+ while (UpdateListHead != nullptr && !Miranda_IsTerminated()) {
+ if (AvatarCheck != nullptr)
+ CheckCurrentFeedAvatar(UpdateGetFirst());
+ else
+ CheckCurrentFeed(UpdateGetFirst());
+ }
+
+ // exit the update thread
+ ThreadRunning = FALSE;
+
+ CoUninitialize();
+}
diff --git a/protocols/NewsAggregator/Src/Utils.cpp b/protocols/NewsAggregator/Src/Utils.cpp
new file mode 100644
index 0000000000..80248ba48f
--- /dev/null
+++ b/protocols/NewsAggregator/Src/Utils.cpp
@@ -0,0 +1,445 @@
+/*
+Copyright (C) 2012 Mataes
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include "stdafx.h"
+
+HNETLIBUSER hNetlibUser = nullptr;
+HNETLIBCONN hNetlibHttp;
+bool UpdateListFlag = FALSE;
+
+bool IsMyContact(MCONTACT hContact)
+{
+ const char *szProto = GetContactProto(hContact);
+ return szProto != nullptr && mir_strcmp(MODULENAME, szProto) == 0;
+}
+
+void NetlibInit()
+{
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_HTTPCONNS | NUF_UNICODE;
+ nlu.szDescriptiveName.w = TranslateT("NewsAggregator HTTP connections");
+ nlu.szSettingsModule = MODULENAME;
+ hNetlibUser = Netlib_RegisterUser(&nlu);
+}
+
+void NetlibUnInit()
+{
+ Netlib_CloseHandle(hNetlibUser);
+ hNetlibUser = nullptr;
+}
+
+void GetNewsData(wchar_t *tszUrl, char **szData, MCONTACT hContact, CFeedEditor *pEditDlg)
+{
+ Netlib_LogfW(hNetlibUser, L"Getting feed data %s.", tszUrl);
+ NETLIBHTTPREQUEST nlhr = { 0 };
+
+ // initialize the netlib request
+ nlhr.cbSize = sizeof(nlhr);
+ nlhr.requestType = REQUEST_GET;
+ nlhr.flags = NLHRF_DUMPASTEXT | NLHRF_HTTP11 | NLHRF_REDIRECT;
+ if (wcsstr(tszUrl, L"https://") != nullptr)
+ nlhr.flags |= NLHRF_SSL;
+ char *szUrl = mir_u2a(tszUrl);
+ nlhr.szUrl = szUrl;
+ nlhr.nlc = hNetlibHttp;
+
+ // change the header so the plugin is pretended to be IE 6 + WinXP
+ NETLIBHTTPHEADER headers[5];
+ nlhr.headersCount = 4;
+ nlhr.headers = headers;
+ nlhr.headers[0].szName = "User-Agent";
+ nlhr.headers[0].szValue = NETLIB_USER_AGENT;
+ nlhr.headers[1].szName = "Cache-Control";
+ nlhr.headers[1].szValue = "no-cache";
+ nlhr.headers[2].szName = "Pragma";
+ nlhr.headers[2].szValue = "no-cache";
+ nlhr.headers[3].szName = "Connection";
+ nlhr.headers[3].szValue = "close";
+ char auth[256];
+ if (g_plugin.getByte(hContact, "UseAuth", 0) || (pEditDlg && pEditDlg->m_useauth.IsChecked()) /*IsDlgButtonChecked(hwndDlg, IDC_USEAUTH)*/) {
+ nlhr.headersCount++;
+ nlhr.headers[4].szName = "Authorization";
+
+ CreateAuthString(auth, hContact, pEditDlg);
+ nlhr.headers[4].szValue = auth;
+ }
+
+ // download the page
+ NETLIBHTTPREQUEST *nlhrReply = Netlib_HttpTransaction(hNetlibUser, &nlhr);
+ if (nlhrReply) {
+ // if the recieved code is 200 OK
+ if (nlhrReply->resultCode == 200 && nlhrReply->dataLength > 0) {
+ Netlib_LogfW(hNetlibUser, L"Code 200: Succeeded getting feed data %s.", tszUrl);
+ // allocate memory and save the retrieved data
+ *szData = (char *)mir_alloc((size_t)(nlhrReply->dataLength + 2));
+ memcpy(*szData, nlhrReply->pData, (size_t)nlhrReply->dataLength);
+ (*szData)[nlhrReply->dataLength] = 0;
+ }
+ else if (nlhrReply->resultCode == 401) {
+ Netlib_LogfW(hNetlibUser, L"Code 401: feed %s needs auth data.", tszUrl);
+
+ if (CAuthRequest(pEditDlg, hContact).DoModal() == IDOK)
+ GetNewsData(tszUrl, szData, hContact, pEditDlg);
+ }
+ else Netlib_LogfW(hNetlibUser, L"Code %d: Failed getting feed data %s.", nlhrReply->resultCode, tszUrl);
+
+ Netlib_FreeHttpRequest(nlhrReply);
+ }
+ else Netlib_LogfW(hNetlibUser, L"Failed getting feed data %s, no response.", tszUrl);
+
+ mir_free(szUrl);
+}
+
+time_t DateToUnixTime(const char *stamp, bool FeedType)
+{
+ struct tm timestamp;
+ char date[9];
+ int i, y;
+ time_t t;
+
+ if (stamp == nullptr)
+ return 0;
+
+ char *p = NEWSTR_ALLOCA(stamp);
+
+ if (FeedType) {
+ // skip '-' chars
+ int si = 0, sj = 0;
+ while (true) {
+ if (p[si] == '-')
+ si++;
+ else if (!(p[sj++] = p[si++]))
+ break;
+ }
+ }
+ else {
+ char monthstr[4], timezonesign[2];
+ int day, month = 0, year, hour, min, sec, timezoneh, timezonem;
+ if (strchr(p, ',')) {
+ strtok(p, ",");
+ p = strtok(nullptr, ",");
+ sscanf(p + 1, "%d %3s %d %d:%d:%d %1s%02d%02d", &day, &monthstr, &year, &hour, &min, &sec, &timezonesign, &timezoneh, &timezonem);
+ if (!mir_strcmpi(monthstr, "Jan"))
+ month = 1;
+ if (!mir_strcmpi(monthstr, "Feb"))
+ month = 2;
+ if (!mir_strcmpi(monthstr, "Mar"))
+ month = 3;
+ if (!mir_strcmpi(monthstr, "Apr"))
+ month = 4;
+ if (!mir_strcmpi(monthstr, "May"))
+ month = 5;
+ if (!mir_strcmpi(monthstr, "Jun"))
+ month = 6;
+ if (!mir_strcmpi(monthstr, "Jul"))
+ month = 7;
+ if (!mir_strcmpi(monthstr, "Aug"))
+ month = 8;
+ if (!mir_strcmpi(monthstr, "Sep"))
+ month = 9;
+ if (!mir_strcmpi(monthstr, "Oct"))
+ month = 10;
+ if (!mir_strcmpi(monthstr, "Nov"))
+ month = 11;
+ if (!mir_strcmpi(monthstr, "Dec"))
+ month = 12;
+ if (year < 2000)
+ year += 2000;
+ if (!mir_strcmp(timezonesign, "+"))
+ mir_snprintf(p, 4 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1, "%04d%02d%02dT%02d:%02d:%02d", year, month, day, hour - timezoneh, min - timezonem, sec);
+ else if (!mir_strcmp(timezonesign, "-"))
+ mir_snprintf(p, 4 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1, "%04d%02d%02dT%02d:%02d:%02d", year, month, day, hour + timezoneh, min + timezonem, sec);
+ else
+ mir_snprintf(p, 4 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1, "%04d%02d%02dT%02d:%02d:%02d", year, month, day, hour, min, sec);
+ }
+ else if (strchr(p, 'T')) {
+ sscanf(p, "%d-%d-%dT%d:%d:%d", &year, &month, &day, &hour, &min, &sec);
+ mir_snprintf(p, 4 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1, "%04d%02d%02dT%02d:%02d:%02d", year, month, day, hour, min, sec);
+ }
+ else {
+ sscanf(p, "%d-%d-%d %d:%d:%d %1s%02d%02d", &year, &month, &day, &hour, &min, &sec, &timezonesign, &timezoneh, &timezonem);
+ if (!mir_strcmp(timezonesign, "+"))
+ mir_snprintf(p, 4 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1, "%04d%02d%02dT%02d:%02d:%02d", year, month, day, hour - timezoneh, min - timezonem, sec);
+ else if (!mir_strcmp(timezonesign, "-"))
+ mir_snprintf(p, 4 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1, "%04d%02d%02dT%02d:%02d:%02d", year, month, day, hour + timezoneh, min + timezonem, sec);
+ else
+ mir_snprintf(p, 4 + 2 + 2 + 1 + 2 + 1 + 2 + 1 + 2 + 1, "%04d%02d%02dT%02d:%02d:%02d", year, month, day, hour, min, sec);
+ }
+ }
+ // Get the date part
+ for (i = 0; *p != '\0' && i < 8 && isdigit(*p); p++, i++)
+ date[i] = *p;
+
+ // Parse year
+ if (i == 6) {
+ // 2-digit year ( 1970-2069 )
+ y = (date[0] - '0') * 10 + (date[1] - '0');
+ if (y < 70)
+ y += 100;
+ }
+ else if (i == 8) {
+ // 4-digit year
+ y = (date[0] - '0') * 1000 + (date[1] - '0') * 100 + (date[2] - '0') * 10 + date[3] - '0';
+ y -= 1900;
+ }
+ else return 0;
+
+ timestamp.tm_year = y;
+ // Parse month
+ timestamp.tm_mon = (date[i - 4] - '0') * 10 + date[i - 3] - '0' - 1;
+ // Parse date
+ timestamp.tm_mday = (date[i - 2] - '0') * 10 + date[i - 1] - '0';
+
+ // Skip any date/time delimiter
+ for (; *p != '\0' && !isdigit(*p); p++);
+
+ // Parse time
+ if (sscanf(p, "%d:%d:%d", &timestamp.tm_hour, &timestamp.tm_min, &timestamp.tm_sec) != 3)
+ return 0;
+
+ timestamp.tm_isdst = 0; // DST is already present in _timezone below
+ t = mktime(&timestamp);
+
+ _tzset();
+ t -= (time_t)_timezone;
+ return (t >= 0) ? t : 0;
+}
+
+bool DownloadFile(LPCTSTR tszURL, LPCTSTR tszLocal)
+{
+ NETLIBHTTPREQUEST nlhr = { 0 };
+ nlhr.cbSize = sizeof(nlhr);
+ nlhr.requestType = REQUEST_GET;
+ nlhr.flags = NLHRF_DUMPASTEXT | NLHRF_HTTP11;
+ char *szUrl = mir_u2a(tszURL);
+ nlhr.szUrl = szUrl;
+ NETLIBHTTPHEADER headers[4];
+ nlhr.headersCount = 4;
+ nlhr.headers = headers;
+ nlhr.headers[0].szName = "User-Agent";
+ nlhr.headers[0].szValue = NETLIB_USER_AGENT;
+ nlhr.headers[1].szName = "Connection";
+ nlhr.headers[1].szValue = "close";
+ nlhr.headers[2].szName = "Cache-Control";
+ nlhr.headers[2].szValue = "no-cache";
+ nlhr.headers[3].szName = "Pragma";
+ nlhr.headers[3].szValue = "no-cache";
+
+ bool ret = false;
+ NETLIBHTTPREQUEST *pReply = Netlib_HttpTransaction(hNetlibUser, &nlhr);
+ if (pReply) {
+ if ((200 == pReply->resultCode) && (pReply->dataLength > 0)) {
+ char *date = nullptr, *size = nullptr;
+ for (int i = 0; i < pReply->headersCount; i++) {
+ if (!mir_strcmpi(pReply->headers[i].szName, "Last-Modified")) {
+ date = pReply->headers[i].szValue;
+ continue;
+ }
+ else if (!mir_strcmpi(pReply->headers[i].szName, "Content-Length")) {
+ size = pReply->headers[i].szValue;
+ continue;
+ }
+ }
+ if (date != nullptr && size != nullptr) {
+ wchar_t *tsize = mir_a2u(size);
+ struct _stat buf;
+
+ int fh = _wopen(tszLocal, _O_RDONLY);
+ if (fh != -1) {
+ _fstat(fh, &buf);
+ time_t modtime = DateToUnixTime(date, 0);
+ time_t filemodtime = mktime(localtime(&buf.st_atime));
+ if (modtime > filemodtime && buf.st_size != _wtoi(tsize)) {
+ DWORD dwBytes;
+ HANDLE hFile = CreateFile(tszLocal, GENERIC_READ | GENERIC_WRITE, NULL, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+ WriteFile(hFile, pReply->pData, (DWORD)pReply->dataLength, &dwBytes, nullptr);
+ ret = true;
+ if (hFile)
+ CloseHandle(hFile);
+ }
+ _close(fh);
+ }
+ else {
+ DWORD dwBytes;
+ HANDLE hFile = CreateFile(tszLocal, GENERIC_READ | GENERIC_WRITE, NULL, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+ WriteFile(hFile, pReply->pData, (DWORD)pReply->dataLength, &dwBytes, nullptr);
+ ret = true;
+ if (hFile)
+ CloseHandle(hFile);
+ }
+ mir_free(tsize);
+ }
+ else {
+ DWORD dwBytes;
+ HANDLE hFile = CreateFile(tszLocal, GENERIC_READ | GENERIC_WRITE, NULL, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+ WriteFile(hFile, pReply->pData, (DWORD)pReply->dataLength, &dwBytes, nullptr);
+ ret = true;
+ if (hFile)
+ CloseHandle(hFile);
+ }
+ }
+ Netlib_FreeHttpRequest(pReply);
+ }
+
+ mir_free(szUrl);
+
+ return ret;
+}
+
+typedef HRESULT(MarkupCallback)(IHTMLDocument3 *, BSTR &message);
+
+HRESULT TestMarkupServices(BSTR bstrHtml, MarkupCallback *pCallback, BSTR &message)
+{
+ IHTMLDocument3 *pHtmlDocRoot = nullptr;
+
+ // Create the root document -- a "workspace" for parsing.
+ HRESULT hr = CoCreateInstance(CLSID_HTMLDocument, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pHtmlDocRoot));
+ if (SUCCEEDED(hr) && pHtmlDocRoot) {
+ IPersistStreamInit *pPersistStreamInit = nullptr;
+
+ hr = pHtmlDocRoot->QueryInterface(IID_PPV_ARGS(&pPersistStreamInit));
+ if (SUCCEEDED(hr)) {
+ // Initialize the root document to a default state -- ready for parsing.
+ pPersistStreamInit->InitNew();
+
+ IMarkupServices *pMarkupServices = nullptr;
+ hr = pHtmlDocRoot->QueryInterface(IID_PPV_ARGS(&pMarkupServices));
+ if (SUCCEEDED(hr)) {
+ IMarkupPointer *pMarkupBegin = nullptr;
+ IMarkupPointer *pMarkupEnd = nullptr;
+
+ // These markup pointers indicate the insertion point.
+ hr = pMarkupServices->CreateMarkupPointer(&pMarkupBegin);
+ if (SUCCEEDED(hr))
+ hr = pMarkupServices->CreateMarkupPointer(&pMarkupEnd);
+
+ if (SUCCEEDED(hr) && pMarkupBegin && pMarkupEnd) {
+ IMarkupContainer *pMarkupContainer = nullptr;
+
+ // Parse the string -- the markup container contains the parsed HTML.
+ // Markup pointers are updated to point to begining and end of new container.
+ hr = pMarkupServices->ParseString(bstrHtml, 0, &pMarkupContainer, pMarkupBegin, pMarkupEnd);
+ if (SUCCEEDED(hr) && pMarkupContainer) {
+ IHTMLDocument3 *pHtmlDoc = nullptr;
+
+ // Retrieve the document interface to the markup container.
+ hr = pMarkupContainer->QueryInterface(IID_PPV_ARGS(&pHtmlDoc));
+ if (SUCCEEDED(hr) && pHtmlDoc) {
+ // Invoke the user-defined action for this new fragment.
+ hr = pCallback(pHtmlDoc, message);
+
+ // Clean up.
+ pHtmlDoc->Release();
+ }
+ pMarkupContainer->Release();
+ }
+ pMarkupEnd->Release();
+ }
+ if (pMarkupBegin)
+ pMarkupBegin->Release();
+ pMarkupServices->Release();
+ }
+ pPersistStreamInit->Release();
+ }
+ pHtmlDocRoot->Release();
+ }
+ return hr;
+}
+
+HRESULT TestDocumentText(IHTMLDocument3 *pHtmlDoc, BSTR &message)
+{
+ IHTMLDocument2 *pDoc = nullptr;
+ IHTMLElement *pElem = nullptr;
+ BSTR bstrId = SysAllocString(L"test");
+
+ HRESULT hr = pHtmlDoc->QueryInterface(IID_PPV_ARGS(&pDoc));
+ if (SUCCEEDED(hr) && pDoc) {
+ hr = pDoc->get_body(&pElem);
+ if (SUCCEEDED(hr) && pElem) {
+ BSTR bstrText = nullptr;
+ pElem->get_innerText(&bstrText);
+ message = SysAllocString(bstrText);
+ SysFreeString(bstrText);
+ pElem->Release();
+ }
+
+ pDoc->Release();
+ }
+
+ SysFreeString(bstrId);
+ return hr;
+}
+
+LPCTSTR ClearText(CMStringW &result, const wchar_t *message)
+{
+ BSTR bstrHtml = SysAllocString(message), bstrRes = SysAllocString(L"");
+ HRESULT hr = TestMarkupServices(bstrHtml, &TestDocumentText, bstrRes);
+ if (SUCCEEDED(hr))
+ result = bstrRes;
+ else
+ result = message;
+ SysFreeString(bstrHtml);
+ SysFreeString(bstrRes);
+
+ result.Replace(L"&#163;", L"£"); //pound
+ result.Replace(L"&#178;", L"²"); //sup2
+ result.Replace(L"&#228;", L"ä"); //auml
+ result.Replace(L"&#233;", L"é"); //latin small letter e with acute
+ result.Replace(L"&#235;", L"ë"); //euml
+ result.Replace(L"&#246;", L"ö"); //ouml
+ result.Replace(L"&#382;", L"ž"); //Latin Small Letter Z With Caron
+ result.Replace(L"&#665;", L"ʙ"); //latin letter small capital b
+ result.Replace(L"&#774;", L"˘"); //Combining Breve
+ result.Replace(L"&#769;", L"´"); //Combining Acute Accent острое ударение
+ result.Replace(L"&#959;", L"ό"); // greek small letter omicron with tonos
+ result.Replace(L"&#1123;", L"ѣ"); //Cyrillic Small Letter Yat
+ result.Replace(L"&#1180;", L"Ҝ"); //cyrillic capital letter ka with vertical stroke
+ result.Replace(L"&#8203;", L"");
+ result.Replace(L"&#8206;", L""); //lrm
+ result.Replace(L"&#8207;", L""); //rlm
+ result.Replace(L"&#8209;", L"‑"); //Non-Breaking Hyphen
+ result.Replace(L"&#8227;", L"‣"); //Triangular Bullet
+ result.Replace(L"&#8722;", L"−"); //minus
+ result.Replace(L"&#9786;", L"☺"); //White Smiling Face
+ result.Replace(L"&#65279;", L"");
+
+ result.Trim();
+
+ return result;
+}
+
+MCONTACT GetContactByNick(const wchar_t *nick)
+{
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrW contactNick(g_plugin.getWStringA(hContact, "Nick"));
+ if (!mir_wstrcmpi(contactNick, nick))
+ return hContact;
+ }
+ return 0;
+}
+
+MCONTACT GetContactByURL(const wchar_t *url)
+{
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrW contactURL(g_plugin.getWStringA(hContact, "URL"));
+ if (!mir_wstrcmpi(contactURL, url))
+ return hContact;
+ }
+ return 0;
+}
diff --git a/protocols/NewsAggregator/Src/resource.h b/protocols/NewsAggregator/Src/resource.h
new file mode 100644
index 0000000000..131a0844ba
--- /dev/null
+++ b/protocols/NewsAggregator/Src/resource.h
@@ -0,0 +1,57 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by c:\Temp\Miranda NG\plugins\NewsAggregator\res\Resource.rc
+//
+#define IDD_OPTIONS 101
+#define IDD_AUTHENTICATION 102
+#define IDI_ICON 109
+#define IDD_ADDFEED 110
+#define IDI_CHECKALL 111
+#define IDI_ADDFEED 112
+#define IDI_IMPORTFEEDS 113
+#define IDI_EXPORTFEEDS 114
+#define IDI_ENABLED 115
+#define IDI_DISABLED 116
+#define IDD_FEEDEXPORT 140
+#define IDD_FEEDIMPORT 141
+#define IDC_TIMEOUT_VALUE_SPIN 1035
+#define IDC_FEEDLIST 1036
+#define IDC_ADD 1037
+#define IDC_CHANGE 1038
+#define IDC_REMOVE 1039
+#define IDC_IMPORT 1040
+#define IDC_EXPORT 1041
+#define IDC_FEEDTITLE 1042
+#define IDC_FEEDURL 1043
+#define IDC_CHECKTIME 1044
+#define IDC_DISCOVERY 1045
+#define IDC_USEAUTH 1046
+#define IDC_LOGIN 1047
+#define IDC_PASSWORD 1048
+#define IDC_TAGSEDIT 1049
+#define IDC_RESET 1050
+#define IDC_TAGHELP 1051
+#define IDC_STARTUPRETRIEVE 1052
+#define IDC_FEEDUSERNAME 1105
+#define IDC_FEEDPASSWORD 1106
+#define IDC_FEEDSLIST 1108
+#define IDC_FEEDSEXPORTLIST 1109
+#define IDC_ADDFEED 1110
+#define IDC_REMOVEFEED 1111
+#define IDC_ADDALLFEEDS 1112
+#define IDC_REMOVEALLFEEDS 1113
+#define IDC_IMPORTFILEPATH 1114
+#define IDC_BROWSEIMPORTFILE 1115
+#define IDC_FEEDSIMPORTLIST 1117
+#define IDC_FEEDNAME 1124
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 117
+#define _APS_NEXT_COMMAND_VALUE 40075
+#define _APS_NEXT_CONTROL_VALUE 1053
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/NewsAggregator/Src/stdafx.cxx b/protocols/NewsAggregator/Src/stdafx.cxx
new file mode 100644
index 0000000000..1b563fc866
--- /dev/null
+++ b/protocols/NewsAggregator/Src/stdafx.cxx
@@ -0,0 +1,18 @@
+/*
+Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org)
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation version 2
+of the License.
+
+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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h" \ No newline at end of file
diff --git a/protocols/NewsAggregator/Src/stdafx.h b/protocols/NewsAggregator/Src/stdafx.h
new file mode 100644
index 0000000000..819e96d69f
--- /dev/null
+++ b/protocols/NewsAggregator/Src/stdafx.h
@@ -0,0 +1,167 @@
+/*
+Copyright (C) 2012 Mataes
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#pragma once
+
+// Windows Header Files:
+#include <windows.h>
+#include <commctrl.h>
+#include <time.h>
+#include <malloc.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+#include <mshtml.h>
+
+// Miranda header files
+#include <newpluginapi.h>
+#include <m_clist.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#include <m_protosvc.h>
+#include <m_protoint.h>
+#include <m_database.h>
+#include <m_netlib.h>
+#include <m_icolib.h>
+#include <m_message.h>
+#include <win2k.h>
+#include <m_xml.h>
+#include <m_avatars.h>
+#include <m_hotkeys.h>
+#include <m_gui.h>
+
+#include <m_folders.h>
+#include <m_toptoolbar.h>
+
+#include "Options.h"
+#include "version.h"
+#include "resource.h"
+
+#define MODULENAME "NewsAggregator"
+#define TAGSDEFAULT L"#<title>#\r\n#<link>#\r\n#<description>#"
+#define DEFAULT_AVATARS_FOLDER "NewsAggregator"
+#define DEFAULT_UPDATE_TIME 60
+
+extern CDlgBase *pAddFeedDialog, *pImportDialog, *pExportDialog;
+extern HNETLIBUSER hNetlibUser;
+extern UINT_PTR timerId;
+extern LIST<CFeedEditor> g_arFeeds;
+// check if Feeds is currently updating
+extern bool ThreadRunning;
+extern bool UpdateListFlag;
+extern wchar_t tszRoot[MAX_PATH];
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
+
+//============ STRUCT USED TO MAKE AN UPDATE LIST ============
+
+struct NEWSCONTACTLIST {
+ MCONTACT hContact;
+ struct NEWSCONTACTLIST *next;
+};
+
+typedef struct NEWSCONTACTLIST UPDATELIST;
+
+extern UPDATELIST *UpdateListHead;
+extern UPDATELIST *UpdateListTail;
+
+void UpdateListAdd(MCONTACT hContact);
+void UpdateThreadProc(void*);
+void DestroyUpdateList(void);
+
+extern HANDLE hUpdateMutex;
+extern HGENMENU hService2[7];
+
+int NewsAggrInit(WPARAM wParam,LPARAM lParam);
+int OptInit(WPARAM wParam, LPARAM lParam);
+int NewsAggrPreShutdown(WPARAM wParam,LPARAM lParam);
+void NetlibInit();
+void NetlibUnInit();
+void InitMenu();
+void InitIcons();
+HICON LoadIconEx(const char* name, bool big);
+HANDLE GetIconHandle(const char* name);
+
+INT_PTR NewsAggrGetName(WPARAM wParam, LPARAM lParam);
+INT_PTR NewsAggrGetCaps(WPARAM wp, LPARAM lp);
+INT_PTR NewsAggrSetStatus(WPARAM wp, LPARAM /*lp*/);
+INT_PTR NewsAggrGetStatus(WPARAM/* wp*/, LPARAM/* lp*/);
+INT_PTR NewsAggrLoadIcon(WPARAM wParam, LPARAM lParam);
+INT_PTR NewsAggrGetInfo(WPARAM wParam, LPARAM lParam);
+INT_PTR NewsAggrGetAvatarInfo(WPARAM wParam, LPARAM lParam);
+INT_PTR NewsAggrRecvMessage(WPARAM wParam, LPARAM lParam);
+
+INT_PTR CheckAllFeeds(WPARAM wParam, LPARAM lParam);
+INT_PTR AddFeed(WPARAM wParam, LPARAM lParam);
+INT_PTR ChangeFeed(WPARAM wParam, LPARAM lParam);
+INT_PTR ImportFeeds(WPARAM wParam, LPARAM lParam);
+INT_PTR ExportFeeds(WPARAM wParam, LPARAM lParam);
+INT_PTR CheckFeed(WPARAM wParam, LPARAM lParam);
+INT_PTR EnableDisable(WPARAM wParam, LPARAM lParam);
+int OnToolbarLoaded(WPARAM wParam, LPARAM lParam);
+void CALLBACK timerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
+void CALLBACK timerProc2(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
+
+bool IsMyContact(MCONTACT hContact);
+void GetNewsData(wchar_t *szUrl, char **szData, MCONTACT hContact, CFeedEditor *pEditDlg);
+time_t DateToUnixTime(const char *stamp, bool FeedType);
+void CheckCurrentFeed(MCONTACT hContact);
+void CheckCurrentFeedAvatar(MCONTACT hContact);
+LPCTSTR CheckFeed(wchar_t* tszURL, CFeedEditor *pEditDlg);
+void UpdateMenu(bool State);
+LPCTSTR ClearText(CMStringW &value, const wchar_t *message);
+bool DownloadFile(LPCTSTR tszURL, LPCTSTR tszLocal);
+void CreateAuthString(char *auth, MCONTACT hContact, CFeedEditor *pDlg);
+MCONTACT GetContactByNick(const wchar_t *nick);
+MCONTACT GetContactByURL(const wchar_t *url);
+
+// =============== NewsAggregator SERVICES ================
+// Check all Feeds info
+// WPARAM = LPARAM = NULL
+#define MS_NEWSAGGREGATOR_CHECKALLFEEDS "NewsAggregator/CheckAllFeeds"
+
+// Add new Feed channel
+// WPARAM = LPARAM = NULL
+#define MS_NEWSAGGREGATOR_ADDFEED "NewsAggregator/AddNewsFeed"
+
+// Change Feed channel
+// WPARAM = LPARAM = NULL
+#define MS_NEWSAGGREGATOR_CHANGEFEED "NewsAggregator/ChangeNewsFeed"
+
+// Import Feed channels from file
+// WPARAM = LPARAM = NULL
+#define MS_NEWSAGGREGATOR_IMPORTFEEDS "NewsAggregator/ImportFeeds"
+
+// Export Feed channels to file
+// WPARAM = LPARAM = NULL
+#define MS_NEWSAGGREGATOR_EXPORTFEEDS "NewsAggregator/ExportFeeds"
+
+// Check Feed info
+// WPARAM = LPARAM = NULL
+#define MS_NEWSAGGREGATOR_CHECKFEED "NewsAggregator/CheckFeed"
+
+// Enable/disable getting feed info
+// WPARAM = LPARAM = NULL
+#define MS_NEWSAGGREGATOR_ENABLED "NewsAggregator/Enabled"
diff --git a/protocols/NewsAggregator/Src/version.h b/protocols/NewsAggregator/Src/version.h
new file mode 100644
index 0000000000..a7d2126e30
--- /dev/null
+++ b/protocols/NewsAggregator/Src/version.h
@@ -0,0 +1,13 @@
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 1
+#define __RELEASE_NUM 0
+#define __BUILD_NUM 5
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "News aggregator"
+#define __FILENAME "NewsAggregator.dll"
+#define __DESCRIPTION "RSS/Atom news aggregator."
+#define __AUTHOR "Mataes, FREAK_THEMIGHTY"
+#define __AUTHORWEB "https://miranda-ng.org/p/NewsAggregator/"
+#define __COPYRIGHT "© 2012-19 Mataes, FREAK_THEMIGHTY"
diff --git a/protocols/NewsAggregator/docs/AtomText.txt b/protocols/NewsAggregator/docs/AtomText.txt
new file mode 100644
index 0000000000..f6d2723822
--- /dev/null
+++ b/protocols/NewsAggregator/docs/AtomText.txt
@@ -0,0 +1,482 @@
+<?xml version="1.0"?>
+
+<feed xmlns="http://www.w3.org/2005/Atom">
+ <updated>2012-01-04T06:45:38Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic</id>
+
+ <title>watcher-miranda project updates - Google Code</title>
+
+ <link rel="self" type="application/atom+xml;type=feed" href="http://code.google.com/feeds/p/watcher-miranda/updates/basic"/>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/updates/list"/>
+
+ <entry>
+ <updated>2012-01-04T06:45:38Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12pftbjzm31hlgp204cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-0.10.latest-vc2010_x64-static.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-0.10.latest-vc2010_x64-static.7z&quot;&gt;miranda-0.10.latest-vc2010_x64-static.7z&lt;/a&gt; (Miranda IM 0.10.0 Alpha #2 VC2010 x64) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2012-01-03T21:06:03Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12qdzfqdumlchjgm04cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-v0100a2w11.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-v0100a2w11.7z&quot;&gt;miranda-v0100a2w11.7z&lt;/a&gt; (T - ) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2012-01-03T20:47:25Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z135ypx45kehgtcq304cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-v0100a2w11.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda-v0100a2w11.7z&quot;&gt;miranda-v0100a2w11.7z&lt;/a&gt; (Miranda IM 0.10.0 Alpha #2 VC6111) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2012-01-03T09:21:55Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12szb1zzybuejnnv22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=mirotr1.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=mirotr1.7z&quot;&gt;mirotr1.7z&lt;/a&gt; (Miranda IM 0.10.0 Alpha #2 VC6) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2012-01-02T20:12:28Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12ltxpzuvr4xvahk04cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda32.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=miranda32.exe&quot;&gt;miranda32.exe&lt;/a&gt; (Miranda32 v.0.9.40.0) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2012-01-01T18:00:06Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13idtjadwu5y3q2322pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.1.0.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.1.0.exe&quot;&gt;Miranda IM Watcher Pack v3.1.0.exe&lt;/a&gt; (Miranda IM Watcher Pack v3.1.0) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Type-Installer&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;OpSys-Windows&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-30T11:06:47Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12vzfygpwqng3m3b22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda_Empoli_Pack_Mod.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda_Empoli_Pack_Mod.exe&quot;&gt;Miranda_Empoli_Pack_Mod.exe&lt;/a&gt; (Miranda IM Empoli Pack Mod v.2.2 (core 0.9.39)) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-29T14:08:24Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z135in4x1yi1fd2ou04cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=mirotr.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=mirotr.7z&quot;&gt;mirotr.7z&lt;/a&gt; (MirOTR 0.11.0.3) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-25T10:59:24Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13dgrs5elfkfp0n122pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=LangpackSuite.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=LangpackSuite.exe&quot;&gt;LangpackSuite.exe&lt;/a&gt; (Test upload) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-25T10:58:18Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13cu14hyzzawjmev22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=LangpackSuite.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=LangpackSuite.exe&quot;&gt;LangpackSuite.exe&lt;/a&gt; (Test) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-21T21:55:28Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12sh1jqflzkj3ofd22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.9.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.9.exe&quot;&gt;Miranda IM Watcher Pack v3.0.9.exe&lt;/a&gt; (Miranda IM Watcher Pack v3.0.9) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Type-Installer&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;OpSys-Windows&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-13T19:46:02Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13nxvbpft3ezr5ps04cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.8.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.8.exe&quot;&gt;Miranda IM Watcher Pack v3.0.8.exe&lt;/a&gt; (Miranda IM Watcher Pack v3.0.8) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Type-Installer&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;OpSys-Windows&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-04T10:52:49Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13vubiqswqqe1cf222pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Fingerprint.dll" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Fingerprint.dll&quot;&gt;Fingerprint.dll&lt;/a&gt; (Fingerprint.dll WP update) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html"></content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-04T10:52:32Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z125fjy5qruixxloh04cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=PackUpdater.dll" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=PackUpdater.dll&quot;&gt;PackUpdater.dll&lt;/a&gt; (PackUpdater.dll WP update) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html"></content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-03T15:01:42Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13etferquvuyzd0z22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=packupdater.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=packupdater.7z&quot;&gt;packupdater.7z&lt;/a&gt; (Pack Updater 0.0.1.0) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-12-02T22:21:54Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z12ysnhy4zi2wvudo22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=fingerprintmodplus.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=fingerprintmodplus.7z&quot;&gt;fingerprintmodplus.7z&lt;/a&gt; (Fingerprint Mod Plus 0.2.2.4 (latest svn revision)) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-11-28T06:15:02Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13hy1xpcr2hgbrfv22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.7.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.7.exe&quot;&gt;Miranda IM Watcher Pack v3.0.7.exe&lt;/a&gt; (Miranda IM Watcher Pack v3.0.7) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Type-Installer&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;OpSys-Windows&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-11-24T16:35:48Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13mcvxqurmeybypn04cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.6.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.6.exe&quot;&gt;Miranda IM Watcher Pack v3.0.6.exe&lt;/a&gt; (Miranda IM Watcher Pack v3.0.6) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Type-Installer&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;OpSys-Windows&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-11-23T04:58:16Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13rxxbauu3wxtfmz22pfv4p3ma4ch5kj</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=simplestatusmsg.7z" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=simplestatusmsg.7z&quot;&gt;simplestatusmsg.7z&lt;/a&gt; (Simple Status Message 1.9.0.4) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+ <entry>
+ <updated>2011-11-19T06:13:19Z</updated>
+ <id>http://code.google.com/feeds/p/watcher-miranda/updates/basic/z13di1rprvjfhpta004cepjgmoicsl1oq1w</id>
+ <link rel="alternate" type="text/html" href="http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.5.exe" />
+ <title type="html">&lt;a class=&quot;ot-download-link&quot; href=&quot;http://code.google.com/p/watcher-miranda/downloads/detail?name=Miranda%20IM%20Watcher%20Pack%20v3.0.5.exe&quot;&gt;Miranda IM Watcher Pack v3.0.5.exe&lt;/a&gt; (Miranda IM Watcher Pack v3.0.5) file uploaded by &lt;a class=&quot;ot-profile-link-2&quot; href=&quot;http://code.google.com/u/watcherhd/&quot;&gt;watcherhd&lt;/a&gt;</title>
+ <author>
+ <name>watcherhd</name>
+ </author>
+ <category term="ProjectNewDownload" scheme="http://code.google.com/updates/type"/>
+ <content type="html">&lt;div class=&quot;ot-labels-field-wrapper&quot;&gt;
+ &lt;span class=&quot;ot-labels-field-name&quot;&gt;Labels: &lt;/span&gt;
+ &lt;span class=&quot;ot-labels-field-value&quot;&gt;
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Featured&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;Type-Installer&lt;/span&gt;
+
+
+
+ &lt;span class=&quot;ot-field-label&quot;&gt;OpSys-Windows&lt;/span&gt;
+
+
+ &lt;/span&gt;
+ &lt;/div&gt;</content>
+</entry>
+
+
+</feed>
diff --git a/protocols/NewsAggregator/docs/RssText.txt b/protocols/NewsAggregator/docs/RssText.txt
new file mode 100644
index 0000000000..b3334ea219
--- /dev/null
+++ b/protocols/NewsAggregator/docs/RssText.txt
@@ -0,0 +1,713 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<rss version="2.0"
+ xmlns:atom="http://www.w3.org/2005/Atom"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:content="http://purl.org/rss/1.0/modules/content/">
+ <channel>
+ <title>Bash.Org.Ru</title>
+ <link>http://bash.org.ru/</link>
+ <atom:link href="http://bash.org.ru/rss/" rel="self" type="application/rss+xml" />
+ <description>Цитатник Рунета</description>
+ <language>ru</language>
+ <item>
+ <guid isPermaLink="false">b3cf2d64d57bdfea405b43426ec354e4b89a98912c71f243c93568020e2f0a70</guid>
+ <link>http://bash.org.ru/quote/414990</link>
+ <title>Цитата #414990</title>
+ <pubDate>Fri, 30 Dec 2011 12:12:01 +0400</pubDate>
+ <description><![CDATA[xxx: Это все равно что брызгать на порнобаннер святой водой, а потом, когда монитор закоротит, кричать, мол, дьявольское устройство не вынесло присутствия святого духа<br>]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">9f3028db6c6020de238a5d27b14d85c21e5f4c8a5f96506b757925df8500c940</guid>
+ <link>http://bash.org.ru/quote/414989</link>
+ <title>Цитата #414989</title>
+ <pubDate>Fri, 30 Dec 2011 11:45:18 +0400</pubDate>
+ <description><![CDATA[В полной мере осознал, что перешел на ночной образ жизни, когда отец разбудил в час ночи с вопросами: &quot;Ты чего спишь? Не заболел случаем?&quot;]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">c917324b76e57d2d6103af4b154f41fb335e9a4cc3f973b0b077a8c857c1353a</guid>
+ <link>http://bash.org.ru/quote/414988</link>
+ <title>Цитата #414988</title>
+ <pubDate>Fri, 30 Dec 2011 11:44:38 +0400</pubDate>
+ <description><![CDATA[ххх: ну как тебе фильм?<br>ууу: конец тру<br>ххх: ты фильм не перепутал?<br>ууу: черт, в смысле, финал меня приятно удивил)]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">96b70712a7185b7d1167f6f9aee454841a4246b0f270185ea3f29d034b9bd39f</guid>
+ <link>http://bash.org.ru/quote/414987</link>
+ <title>Цитата #414987</title>
+ <pubDate>Fri, 30 Dec 2011 11:44:01 +0400</pubDate>
+ <description><![CDATA[Отзыв о телефоне с сенсорным экраном:<br>Света:<br>Купила его в ***. Классный телефон!!! Ещё не разобралась, как снять блокировку с экрана. Он красивый.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">793886d798688d3e6bec7d2ffb51d6397f356e5c0e00ef06d07f22b87643c93a</guid>
+ <link>http://bash.org.ru/quote/414986</link>
+ <title>Цитата #414986</title>
+ <pubDate>Fri, 30 Dec 2011 11:13:16 +0400</pubDate>
+ <description><![CDATA[xxx: сегодня пришла посылка посылка с ebay в которой 50шт наклеек от ipad. Теперь у меня iДом, а в нем iУнитаз, iШкаф, iХолодильник и даже iКот куда то убежал....]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">6eac3f54c4f58d8a41c7e7f72f72ca6e0c6bf5869f0eefc99044ef4427db28d0</guid>
+ <link>http://bash.org.ru/quote/414985</link>
+ <title>Цитата #414985</title>
+ <pubDate>Fri, 30 Dec 2011 11:12:02 +0400</pubDate>
+ <description><![CDATA[xxx: отдам 4-х котят в любые руки, им уже 3 месяца и они всех задолбали.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">744d1d505dce7f1877c45baee1fdf97009a403d6dedb3ae1cd185480ec3dbbd0</guid>
+ <link>http://bash.org.ru/quote/414984</link>
+ <title>Цитата #414984</title>
+ <pubDate>Fri, 30 Dec 2011 11:11:01 +0400</pubDate>
+ <description><![CDATA[xxx:<br>Где купить кормовых мышей (лысых)?<br>На зоорынке нету.<br><br>yyy:<br>Довели страну... Народ уже мышей жрать начал.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">aadc7f6194e8062c44250a9a878f010c0fe7d9d95af9a8389fbf8a8f748d6c6f</guid>
+ <link>http://bash.org.ru/quote/414983</link>
+ <title>Цитата #414983</title>
+ <pubDate>Fri, 30 Dec 2011 10:45:08 +0400</pubDate>
+ <description><![CDATA[xxx: у нас ёлка не простая, понтовая<br>xxx: с оптоволокном и светится<br>yyy: wifi бесплатно не раздает?]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">01511c230d7cdf4ed42f09106b3075a5021797ae5a11d3063dc9332bb7baf858</guid>
+ <link>http://bash.org.ru/quote/414982</link>
+ <title>Цитата #414982</title>
+ <pubDate>Fri, 30 Dec 2011 10:44:36 +0400</pubDate>
+ <description><![CDATA[Darkforce: А ты к экзамену с музыкой готовишься?<br>Ergo: Да. И с включенной асей. Не бери с меня пример.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">cc05613e48d3f285e2a2a95a12f542586c5c0fe4499addf3c2a633cf4940e572</guid>
+ <link>http://bash.org.ru/quote/414981</link>
+ <title>Цитата #414981</title>
+ <pubDate>Fri, 30 Dec 2011 10:44:01 +0400</pubDate>
+ <description><![CDATA[&lt;Jakiro&gt; сегодня вешал гирлянду, запутался в ней, сел, пришла сестра, включила гирлянду и пошла ржать :(]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">589fe99078c1447d672503cd8ffb9ba7524d9bd9e03cb5444e7c6fcd2be55269</guid>
+ <link>http://bash.org.ru/quote/414980</link>
+ <title>Цитата #414980</title>
+ <pubDate>Fri, 30 Dec 2011 10:12:44 +0400</pubDate>
+ <description><![CDATA[SeeR: Если считать коэффициент лени равным отношению того, что нужно было сделать, к тому, что сделано, то по воскресеньям я традиционно делю на ноль.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">58b960aeadb0e2700dd3ec5c18a0f9ca1f446d49f66edabf2ad3ea0f4a9f4933</guid>
+ <link>http://bash.org.ru/quote/414979</link>
+ <title>Цитата #414979</title>
+ <pubDate>Fri, 30 Dec 2011 10:12:01 +0400</pubDate>
+ <description><![CDATA[Стина: Глупо было принимать ванну с бомбочкой с блестками. Мы в блестках, полотенца в блестках, постельное белье в блестках, даже кошка уже в блестках.<br>Но еще глупее было наутро идти к гинекологу! &gt;.&lt;]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">dda44cf9be0c8bf4691ce24629fd67dca371952e1dc45aa5dc1cce16ca095d29</guid>
+ <link>http://bash.org.ru/quote/414978</link>
+ <title>Цитата #414978</title>
+ <pubDate>Fri, 30 Dec 2011 09:46:04 +0400</pubDate>
+ <description><![CDATA[BaDMaN: ненавижу утро субботы. Правда, оно не всегда утром и не всегда в субботу.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">33f18d83baf27fbd1e28e525c942b2c7e379b42a7d91f7436e2e199400ceda30</guid>
+ <link>http://bash.org.ru/quote/414977</link>
+ <title>Цитата #414977</title>
+ <pubDate>Fri, 30 Dec 2011 09:45:01 +0400</pubDate>
+ <description><![CDATA[ХХХ: Скайримские норды такие брутальные, что суровые челябинские мужики по сравнению с ними девочки из песочницы. Но при этом в каждой пещере самого жестокого разбойника, в каждом доме самого яростного норда на столе или полке стоит сладкий рулет.<br>УУУ: Рулетики фигня. Все тамриэльские разбойники и мародёры поддерживают среди себя высокую грамотность и даже в самом распропащем, заросшем мхом и паутиной логове всегда есть две-три книжечки. Вот так приходит брутальный скайримский дорожный разбойник после тяжёлого трудового будня, садится на хлипкий табуретик, берёт сладкий рулетик и читает &quot;краткую историю империи&quot;. брутальненько.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">5599090163fe32efddbf295e457fd9cc4f3426b524eebaaaa4fa8277f34e9be2</guid>
+ <link>http://bash.org.ru/quote/414976</link>
+ <title>Цитата #414976</title>
+ <pubDate>Fri, 30 Dec 2011 09:13:01 +0400</pubDate>
+ <description><![CDATA[xxx: мой друг каждую субботу ходит в кинотеатр!<br>yyy: торренты замаливает?]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">1bb26a5bc553b0570cbdf64be1a9ba3af74c3fd64dc60fe0bf9335ecb74600d0</guid>
+ <link>http://bash.org.ru/quote/414975</link>
+ <title>Цитата #414975</title>
+ <pubDate>Fri, 30 Dec 2011 08:45:35 +0400</pubDate>
+ <description><![CDATA[xxx: Маленький Петя очень любит подарки. Его мама подарила ему на день рождения две строки равной длины, состоящие из больших и маленьких букв латинского алфавита. Теперь Петя хочет сравнить эти строки лексикографически. Помогите Пете выполнить сравнение. (facepalm)<br>yyy: Помогите Пете не закончить жизнь суицидом :D]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">cf4da48b55d3fdb9e9825e39a664bd4d41dc5c7a64227796ad1afb0900bdec19</guid>
+ <link>http://bash.org.ru/quote/414974</link>
+ <title>Цитата #414974</title>
+ <pubDate>Fri, 30 Dec 2011 08:45:01 +0400</pubDate>
+ <description><![CDATA[Давным-давно, когда ещё не было батареек и аккумуляторов, садилось солнце. Его тоже хватало от силы на день, не больше.<br>]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">1a7a8ba066100acdf40b79f4fbc967932320641e3565b230678920432e80e1e3</guid>
+ <link>http://bash.org.ru/quote/414973</link>
+ <title>Цитата #414973</title>
+ <pubDate>Fri, 30 Dec 2011 08:12:44 +0400</pubDate>
+ <description><![CDATA[xxx: только в армии понимаешь, что зубная щетка реально для труднодоступных мест...]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">339e00558b293e087749ba42e0f06916531e712b1edfb25e470e2c0d10494aea</guid>
+ <link>http://bash.org.ru/quote/414972</link>
+ <title>Цитата #414972</title>
+ <pubDate>Fri, 30 Dec 2011 08:11:44 +0400</pubDate>
+ <description><![CDATA[С форума<br><br>XXX: Здравствуйте, скажите пожалуйста, каков срок годности у сигарет?<br>Купил пачку сигарет и чувствую, что какие то они хреновые, сначала подумал, что это связано с тем, что я сейчас пытаюсь бросить курить (раньше курил пачку в день, а щас пачку на неделю тяну) и начал отвыкать, потом глянул на срок изготовления, а там написано июль 2008г...<br><br>YYY: Боитесь навредить здоровью? )))]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">cfa6ff32cedafbf49ef812730e850a6abc9ec61c7682f3518d95fa00db4e1a14</guid>
+ <link>http://bash.org.ru/quote/414971</link>
+ <title>Цитата #414971</title>
+ <pubDate>Fri, 30 Dec 2011 08:11:01 +0400</pubDate>
+ <description><![CDATA[R*: ничо так прога. рабочие места пользователей на схеме можно изобразить очень разнообразно - есть картинки оленя, кенгуру, овцы, жирафа]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">128696d56057a228c43deb8cad49205905868817d0b4e834e37e3fdaccecafb4</guid>
+ <link>http://bash.org.ru/quote/414970</link>
+ <title>Цитата #414970</title>
+ <pubDate>Thu, 29 Dec 2011 12:12:42 +0400</pubDate>
+ <description><![CDATA[xxx: Я такая, какая я есть!!<br>yyy: Да, и глаза у тебя цвета твоих глаз.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">2d15491a51b88af3e66c02b4d326f1e2802656b6361f8f07dd667fbbe9dce728</guid>
+ <link>http://bash.org.ru/quote/414969</link>
+ <title>Цитата #414969</title>
+ <pubDate>Thu, 29 Dec 2011 12:11:34 +0400</pubDate>
+ <description><![CDATA[ххх: Да у меня вообще такое ощущение, что все покупаемые мною средства для укрепления и роста волос не задерживаясь на голове начинают действовать в области нижних конечностей и промежности...]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">ed64e480321c46a51035c44a445cfd98927e2e303d972ac8874e8e36c11a8371</guid>
+ <link>http://bash.org.ru/quote/414968</link>
+ <title>Цитата #414968</title>
+ <pubDate>Thu, 29 Dec 2011 12:11:01 +0400</pubDate>
+ <description><![CDATA[&quot;Почему программисты работают по ночам&quot; @habr<br><br>troydm: Абсолютно согласен с автором, именно поэтому я ложусь спать в 5 утра и просыпаюсь в час дня! Всем спокойной ночи!<br>muzhig: Это можно себе позволить, если нет жены. А вот моей очень не нравится когда я работаю по ночам. Все объяснения про то что «ночью намного лучше работается» она не хочет воспринимать всерьёз.<br>ozgg: Ну жену можно тоже научить программировать, и график синхронизируется ;)<br>Vexilurz: Конечно. Делов-то на 5 минут]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">aaa2f3a8dd486d209a697ecd4e3d728d99a2aa37dd482a3a859af5c473143b69</guid>
+ <link>http://bash.org.ru/quote/414967</link>
+ <title>Цитата #414967</title>
+ <pubDate>Thu, 29 Dec 2011 11:46:07 +0400</pubDate>
+ <description><![CDATA[Нашел на сайте одной научной лаборатории в сотрудниках человека, который лет эдак 16 назад угнал у меня велик. Вот думаю, может сходить, попросить у него велосипед обратно, он же говорил &quot;да я прокачусь вон до туда и верну!&quot; :)))]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">dc470e391715c450eef79e82aaadfb0342ecc256504946f0a32d2f8c1160557e</guid>
+ <link>http://bash.org.ru/quote/414966</link>
+ <title>Цитата #414966</title>
+ <pubDate>Thu, 29 Dec 2011 11:45:06 +0400</pubDate>
+ <description><![CDATA[vova_belkin:<br><br>Вот мой прадедушка, например, ухитрился прокутить и проиграть в карты до копейки все имение, наследство и женино приданое аккурат к 1917 году.<br><br>И с тех пор считался в нашем семействе непререкаемым авторитетом в вопросах распоряжения капиталом.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">a7147227d4c9f64edae338c2cec9f4456a1214ea3f9d899c2486038abe99a8f5</guid>
+ <link>http://bash.org.ru/quote/414965</link>
+ <title>Цитата #414965</title>
+ <pubDate>Thu, 29 Dec 2011 11:44:01 +0400</pubDate>
+ <description><![CDATA[ну-ну: если атеизм - это религия, то не собирать марки - это хобби]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">d35adf64ed961a7e7ff88e11a9b57760b1cd3f0a835f008b6e9782a27ee1a31a</guid>
+ <link>http://bash.org.ru/quote/414964</link>
+ <title>Цитата #414964</title>
+ <pubDate>Thu, 29 Dec 2011 11:13:11 +0400</pubDate>
+ <description><![CDATA[xxx: да ну нахер эту сессию. Пока учил дискретную математику, забыл пароли от двух почтовых ящиков.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">8ce06ad45b760d6b51e2432476e5c13dc9158f589c9b662147b760b0a1b967ac</guid>
+ <link>http://bash.org.ru/quote/414963</link>
+ <title>Цитата #414963</title>
+ <pubDate>Thu, 29 Dec 2011 11:12:01 +0400</pubDate>
+ <description><![CDATA[Обсуждение новой антресоли в кладовке:<br><br>Ну там все как надо сделали. Но барахла традиционно больше, чем места под него. Причем вот в чем загадка бытия: вынимаешь барахло из кладовки, половину выкидываешь, оставшееся убираешь в кладовку, а оно туда не влезает!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">c64eb292881cc760ac0d2f7ac0b1010a8047b1271d39a0bc759076633640bbb4</guid>
+ <link>http://bash.org.ru/quote/414962</link>
+ <title>Цитата #414962</title>
+ <pubDate>Thu, 29 Dec 2011 10:45:24 +0400</pubDate>
+ <description><![CDATA[Lilith: я боюсь готовить кальмара<br>Lightning: почему???<br>Lilith: у него клюв, и еще надо что-то сдирать как чулок<br>Lightning: че ты боишься, там все сходит классно<br>Lilith: вдруг я сдеру кальмара, а съем чулок<br>Lilith: а еще у них там чернильница вроде, и икра<br>Lightning: ну блин, ты потрошила кого-нибудь вообще когда-нибудь?<br>Lilith: я что, похожа на самца кальмара?<br>Lilith: только копченую мойву<br>Lightning: а курицу? не? ее так смешно еще можно надевать на руку и играть в театр<br>Lightning: шевелить крылышками, если через жопу вставить<br>Lightning: так вот, кальмара легче потрошить, он мягонький такой<br>Lightning: и жопы нет]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">19ee3858da403abdebc2f2694ade27e224d83cb2d0325964d802f3313c1333de</guid>
+ <link>http://bash.org.ru/quote/414961</link>
+ <title>Цитата #414961</title>
+ <pubDate>Thu, 29 Dec 2011 10:44:36 +0400</pubDate>
+ <description><![CDATA[муж: да как, как, херово :( не переживу я, наверное, испытательный срок<br>я: почему??<br>муж: да вот блин. решил показать себя в хорошем свете перед шефом. пожелал ему приятного аппетита. а он шел не в столовую а в туалет.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">e0270fd309b6e90cb9f26d9012a1db8ed681fd071f5848b395535442033ffe3a</guid>
+ <link>http://bash.org.ru/quote/414960</link>
+ <title>Цитата #414960</title>
+ <pubDate>Thu, 29 Dec 2011 10:44:01 +0400</pubDate>
+ <description><![CDATA[Luba: Чем занимаешься в отпуске?<br>BreakDancer: Разными важными делами<br>Luba: Например?<br>BreakDancer: Да вот вспомнил, что в детстве у меня был пистолет, стреляющий присосками<br>BreakDancer: и решил, что раз уж я вырос до 29 лет и стал большим<br>BreakDancer: то и присоски тоже должны быть большими!<br>BreakDancer: Сделал арбалет, который стреляет вантусом]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">8187c704ade265c329ccc02384e4206607407657bc6c9b9425a9542f0cb5a6a1</guid>
+ <link>http://bash.org.ru/quote/414959</link>
+ <title>Цитата #414959</title>
+ <pubDate>Thu, 29 Dec 2011 10:13:01 +0400</pubDate>
+ <description><![CDATA[Обещают, что дети, рожденные в год Черного Дракона, будут творческими и активными. Но мы-то знаем, что главное для них - иммунитет к магии!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">1e5eadf8678f61893bcf84e0dfb41290f63266eab736941b7ca07653b70f17d4</guid>
+ <link>http://bash.org.ru/quote/414958</link>
+ <title>Цитата #414958</title>
+ <pubDate>Thu, 29 Dec 2011 09:45:26 +0400</pubDate>
+ <description><![CDATA[Звонит курьер из одной конторы и спрашивает как добраться.<br>Я: далее мост через реку, идете по мосту...<br>К: А река где в это время? Слева? Справа?<br>Я: ВНИЗУ!<br>К: ага, понятно...<br>Я: Дальше переходите на другой берег, спускаетесь на набережную...<br>К: А чё, прямо до конца моста идти? или раньше повернуть?]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">b7c708279640f1efe4ec3401970cb89f075864203ed0fbeeb612e9592655a4c3</guid>
+ <link>http://bash.org.ru/quote/414957</link>
+ <title>Цитата #414957</title>
+ <pubDate>Thu, 29 Dec 2011 09:44:52 +0400</pubDate>
+ <description><![CDATA[gutta_honey@lj<br>Лиза фанат &quot;Звездных войн&quot;. У нее есть фигурка Дарта Вейдера. Но девчонка есть девчонка. Она, как с пупсиком, с ним играет. Вот сегодня:<br>- Дарту Вейдеру нужна квартира! Я его поселю в коробке из-под апельсинов.<br>Вот так в женских руках даже злодеев галактического масштаба постигает судьба чебурашки.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">e91f03e5e391060d916a7e7e827cb6eaeec132c17a1ac5d78af70d5368461ec5</guid>
+ <link>http://bash.org.ru/quote/414956</link>
+ <title>Цитата #414956</title>
+ <pubDate>Thu, 29 Dec 2011 09:44:01 +0400</pubDate>
+ <description><![CDATA[ХХХ: кто рано встаёт, того кот разбудил :(]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">c805cfaf28bf072384933e50ea8e1c48f815063c3bfbfe05a0986d6b944bd14e</guid>
+ <link>http://bash.org.ru/quote/414955</link>
+ <title>Цитата #414955</title>
+ <pubDate>Thu, 29 Dec 2011 09:13:01 +0400</pubDate>
+ <description><![CDATA[XXX: Бежать, бежать отсюда!<br>YYY: Что у тебя там?<br>XXX: Только что коммерческий с исполнительным в кабинете орали друг на друга: &quot;Да я таких как ты в Афгане к стенке ставил&quot; vs &quot;А я таких как ты на зоне петушил&quot;. Мне страшно.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">0636538a5462fc292f9b4fc6439cd6f7f8ab0fe79ba081c47e36d3d8338806fe</guid>
+ <link>http://bash.org.ru/quote/414954</link>
+ <title>Цитата #414954</title>
+ <pubDate>Thu, 29 Dec 2011 08:46:01 +0400</pubDate>
+ <description><![CDATA[xxx: Да ты что, это же баянъ.<br>xxx: Круговорот интернета. В твиттер постят записи пятилетней давности из ЖЖ.<br>yyy: вот не видела, жж обошел меня стороной<br>ххх: Так я и говорю, в ЖЖ постили шутки с форумов, в форумы - с фидо...<br>ххх: и только в фидо основоположники сетевого юмора перепечатывали анекдоты из газет]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">c8591055f839c5dbc882d36e7a4d2db9ce399460048e8e0e6d466dd43a88cae1</guid>
+ <link>http://bash.org.ru/quote/414953</link>
+ <title>Цитата #414953</title>
+ <pubDate>Thu, 29 Dec 2011 08:13:04 +0400</pubDate>
+ <description><![CDATA[О сексе:<br>xxx: отлично! в лабораторных такого не было,но я ЗА! )))<br>yyy: В лабораториях опасно. зацепил не ту колбу - и все, чем гордился всю жизнь и с чем жил - с тихим шипением капает на пол... =(<br>xxx: Или высоковольтная установка по крестцовому сплетению... Струя эякулята пробивает кирпичную стену и ранит лектора в соседней аудитории!<br>xxx: Кажется, я только что придумал классное аниме, да?]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">714be978a8678d201b16981150150166752145feaefa2f159980d76051602d87</guid>
+ <link>http://bash.org.ru/quote/414952</link>
+ <title>Цитата #414952</title>
+ <pubDate>Thu, 29 Dec 2011 08:11:54 +0400</pubDate>
+ <description><![CDATA[Реклама на Яндексе известной компании и слоган &quot;Попробуй с нашим выбиратором подарков!&quot;<br>Ага, я тоже первый раз неправильно прочитал =)]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">dd7d36ba1543a7ac360b28c72f669816d3551bb09f34156635f80efbc9a4f390</guid>
+ <link>http://bash.org.ru/quote/414951</link>
+ <title>Цитата #414951</title>
+ <pubDate>Thu, 29 Dec 2011 08:11:01 +0400</pubDate>
+ <description><![CDATA[Сегодня выносил мусор в офисе, а моя коллега играла в винду, задавая вопросы:<br>- Вы уверены, что хотите очистить корзину? Файлы будут удалены безвозвратно.<br>А потом у меня порвался пакет и весь мусор разлетелся по офису, на что коллега печально заметила:<br>- Произошел сбой при очистке корзины, перезагрузитесь и попробуйте снова...]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">174e14053635b5325be15ae0a37b47953115b33e0d082053064572907d2829a0</guid>
+ <link>http://bash.org.ru/quote/414950</link>
+ <title>Цитата #414950</title>
+ <pubDate>Wed, 28 Dec 2011 12:46:01 +0400</pubDate>
+ <description><![CDATA[[QuizMaster7] Повторяю вопрос: Именно они вешали под шею коня волчью голову, а на седло прикрепряли метлу, чтобы вынюхивать измену и выметать ее из государства<br>[QuizMaster7] Первая подсказка: Количество букв: 9<br>[EwokDoUrden] фигасе!<br>[EwokDoUrden] НАРКОМАНЫ]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">691660b05378e2d242a7a60429e2cd94a44e8d2041b2facb2597cb21ec213fbf</guid>
+ <link>http://bash.org.ru/quote/414949</link>
+ <title>Цитата #414949</title>
+ <pubDate>Wed, 28 Dec 2011 12:13:18 +0400</pubDate>
+ <description><![CDATA[Док: Бля, ходил покурить на балкон, вижу в углу что-то мохнатое с угрожающей тенью. В сторону шарахнулся. И уже думаю, глюки от бессонницы прут. Не блин, я просто забыл, что вчера елку купил.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">634c63c05a37bbb5933ccae9bd50bbc4e04d2a27dfd2895ab8f4be5cc77a5707</guid>
+ <link>http://bash.org.ru/quote/414948</link>
+ <title>Цитата #414948</title>
+ <pubDate>Wed, 28 Dec 2011 12:12:02 +0400</pubDate>
+ <description><![CDATA[XXX: все, финиш! я конечно разных дебилов видела. и к скрепкам в принтере уже даже почти привыкла. и скотч на барабане, блин, приклеенный с честными глазами &quot;ну я же его даже не открывала, я не знаю, как он туда попал!&quot;. но чтобы так! у меня сейчас принтер КАЛЬКУЛЯТОР зажевал!!! калькулятор, блин!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">2309307a0dd79a2f77f63dbbbf3239d5de3cd41409ce23750c0e8ebecd20466f</guid>
+ <link>http://bash.org.ru/quote/414946</link>
+ <title>Цитата #414946</title>
+ <pubDate>Wed, 28 Dec 2011 11:44:57 +0400</pubDate>
+ <description><![CDATA[xxx:<br>отдам в дар плеер<br>Explay T-7, слегка подержаный (вхламину)]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">c58a33a67db26dab4b121d14ebad5cd80d78040eea517835a90bbdc81887b4dc</guid>
+ <link>http://bash.org.ru/quote/414945</link>
+ <title>Цитата #414945</title>
+ <pubDate>Wed, 28 Dec 2011 11:44:01 +0400</pubDate>
+ <description><![CDATA[Купили с сотрудницей в офис ликера. Половину выпили, остатки она заматывает в пакетик и ставит в холодильник.<br>Я: Мы что, тут его и оставим?<br>Сотрудница: Ну да, а что нам терять? )<br>Я: Ну, например работу....]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">3a8ab041c452b16f9f415d3f6d209f1d58f11ed2ab0ee5f928a5f6b8e22a78b9</guid>
+ <link>http://bash.org.ru/quote/414944</link>
+ <title>Цитата #414944</title>
+ <pubDate>Wed, 28 Dec 2011 11:12:55 +0400</pubDate>
+ <description><![CDATA[&lt;Belka&gt; Весьма смутилась, найдя в записной телефонной книжке своего безграмотного брата запись &quot;Макс -сосет&quot;.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">d72696e62bb007bb3004d7403e5915734f7ca02ef54757e08cb0a689a1b4df4d</guid>
+ <link>http://bash.org.ru/quote/414943</link>
+ <title>Цитата #414943</title>
+ <pubDate>Wed, 28 Dec 2011 11:12:01 +0400</pubDate>
+ <description><![CDATA[korsa: вокруг меня три компа, два телефона и навигатор<br>fintar: нужно перевезти их через реку?]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">9ffbfa3d0268a0dc955b9969e4c2b77cc50443a7d6bd9b60f9cf4102daeb7fb1</guid>
+ <link>http://bash.org.ru/quote/414942</link>
+ <title>Цитата #414942</title>
+ <pubDate>Wed, 28 Dec 2011 10:45:41 +0400</pubDate>
+ <description><![CDATA[Из обсуждения:<br>Как–то раз я в споре со своей женой обнаружил какую–то откровенную дурь в ее словах и сказал:<br>— Но это же не логично!<br>— Ну и что?<br>Блядь, НУ И ЧТО? в этот момент у меня вообще весь мир рухнул, и я понял что для нее вообще нет разницы, логично или нет то, что она говорит. ВООБЩЕ!<br><br>Когда я пересказываю это своим друзьям, все хохочут или улыбаются. А когда девушкам — они просто ждут, что я дальше скажу, со внимательным лицом, потому что искренне не замечают проблемы в этой фразе]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">6017310e922bd529b5ad3be09f4f0c5e8b6b2fb76d0bd05b617a8eac0ae27193</guid>
+ <link>http://bash.org.ru/quote/414941</link>
+ <title>Цитата #414941</title>
+ <pubDate>Wed, 28 Dec 2011 10:44:47 +0400</pubDate>
+ <description><![CDATA[xxx: у нас в столовой давно вместо салфеток бумага промышленная нарезана, но сейчас она еще и глянцевая]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">b101af3976aa2e9b7841576433b0c68af93c3ce85ac75383a6f7b20a0106a9c6</guid>
+ <link>http://bash.org.ru/quote/414940</link>
+ <title>Цитата #414940</title>
+ <pubDate>Wed, 28 Dec 2011 10:44:01 +0400</pubDate>
+ <description><![CDATA[Сейчас с женой по телефону разговаривал.<br>Она говорит:<br>- Давай тебе на НГ рубашку пошьем клевую и это будет моим подарком.<br>- Как хочешь.<br>Предлагает мерки поехать снять, я начинаю диктовать.<br>- Длина 174 см, ширина 80 см. Внутри ткань бархат, снаружи дерево, лучше дуб, крышка тоже дубовая резная.<br>Она говорит:<br>- Все записала, сейчас им позвоню.<br>И тут она прочитала то, что записала...]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">1d3da2d78ecf5bac86c480e26d65184e8b69cab96bc8d6c038de7de9ca468ebd</guid>
+ <link>http://bash.org.ru/quote/414939</link>
+ <title>Цитата #414939</title>
+ <pubDate>Wed, 28 Dec 2011 10:13:07 +0400</pubDate>
+ <description><![CDATA[ххх: У нас сегодня экзамен по анатомии вообще зачетный вышел. Один парень срез гортани назвал срезом шейки матки, другой в ромбовидной ямке мозга приметил, звиняюсь, вульву.<br>ххх: Обоих отправили на пересдачу с формулировкой &quot;вылечите недотрах и приходите снова&quot;.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">0365ddac152e7a1f45d4fe35cc5d673ff9e9cbce8d9d125e40b5dca139cd293e</guid>
+ <link>http://bash.org.ru/quote/414938</link>
+ <title>Цитата #414938</title>
+ <pubDate>Wed, 28 Dec 2011 10:12:01 +0400</pubDate>
+ <description><![CDATA[xxx: Жена после суток на работе попросила разбудить ее в 20:00. Звоню, она поднимает трубку, ничего не говорит, слышно только мирное сопение... Выключила будильник, блин :D]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">8774184a10feb87ab76c3eac63fcf6873b572cd376d06b87ec2cafa48464b57b</guid>
+ <link>http://bash.org.ru/quote/414937</link>
+ <title>Цитата #414937</title>
+ <pubDate>Wed, 28 Dec 2011 09:45:31 +0400</pubDate>
+ <description><![CDATA[Ascha: как удобно: если реветь два часа подряд - то тушь смывать уже не нужно!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">5f9e58d114c8a86764bd26780e94bb3f00f0a4db026821f84d06b4540db7b5ed</guid>
+ <link>http://bash.org.ru/quote/414936</link>
+ <title>Цитата #414936</title>
+ <pubDate>Wed, 28 Dec 2011 09:45:01 +0400</pubDate>
+ <description><![CDATA[xxx: я зайду щас?<br>yyy: Я - горячая штучка. И я уже вся теку. Но будь со мной осторожен.<br>xxx: Аня?<br>yyy: У меня температура. Сопли ручьем. Рискуешь заразиться.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">8b1acd9ec8457ac318c78b1dc88005edf4fc9f0ace4d47c1080c1b670de19e2e</guid>
+ <link>http://bash.org.ru/quote/414935</link>
+ <title>Цитата #414935</title>
+ <pubDate>Wed, 28 Dec 2011 09:13:01 +0400</pubDate>
+ <description><![CDATA[Duck: Решил поправить здоровье, записался в бассейн.<br>Dimes: уринотерапия не работает]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">187c05af1edfcce0de5da82d30a58fb83ae474e6fa897ad684bd3ad7c50e9dd7</guid>
+ <link>http://bash.org.ru/quote/414934</link>
+ <title>Цитата #414934</title>
+ <pubDate>Wed, 28 Dec 2011 08:46:02 +0400</pubDate>
+ <description><![CDATA[xxx: Меня попросили в метро пройти через рамку<br>yyy: какого х?<br>xxx: Хрен его знает<br>yyy: ты показался им подозрительным? )<br>xxx: Был как всегда в джинсах чистых ботинках кожаной сумке и наглой рожей<br>xxx: Меня как правило они вообще не замечают<br>yyy: хы<br>yyy: ты был в кожаной сумке, это настораживает]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">00822e572762f43d2fb56ef00c2f7be12f703a27a39949f99036f7734a26f566</guid>
+ <link>http://bash.org.ru/quote/414933</link>
+ <title>Цитата #414933</title>
+ <pubDate>Wed, 28 Dec 2011 08:45:02 +0400</pubDate>
+ <description><![CDATA[misterIT: Сань, привет. срочно нужна помощь, через сколько можешь в офис подгрести?<br>misterIT: Домен рухнул, рейд заглючило. И винт прихвати.<br>misterIT: Сань!!! ты тут?<br>xxx@qip: Тут, собираюсь, а что случилось то? Напряжение? Коротнуло?<br>misterIT: Да хз<br>misterIT: Бороду вчера сбрил, свидание блядь видите ли!<br>xxx@qip: А я свитер постирал. Видимо не врали.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">a6231be02247fcfffbaa07e020f43a4c7a1c7ed628ed86af16443ffe45ed7127</guid>
+ <link>http://bash.org.ru/quote/414932</link>
+ <title>Цитата #414932</title>
+ <pubDate>Wed, 28 Dec 2011 08:12:38 +0400</pubDate>
+ <description><![CDATA[xxx: Женщины - как компьютерные игры с разными уровнями сложности. Если играть на Very Easy - то быстро пропадает интерес к игре. А если играть на Very Hard - то можно натереть мозоли джойстиком.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">039ba4efda1619b3b4374b223e344b3423a8d9788a18bf73ac07bce7bac04bea</guid>
+ <link>http://bash.org.ru/quote/414931</link>
+ <title>Цитата #414931</title>
+ <pubDate>Wed, 28 Dec 2011 08:12:01 +0400</pubDate>
+ <description><![CDATA[Я:<br>Жена мне такая говорит:<br>- мне нужна шуба норковая,<br>- у тебя же есть,<br>- у меня из кусочков, а мне надо цельную, у нас у всей группы уже цельные, а z одна как лошара!<br>- у всей - это у одной Людки?<br>- ну нет, у двоих точно есть!<br>- ... а мне нужен фотоаппарат кэнон 5д марк 2<br>- у тебя же есть уже.<br>- ну так у меня 5д, а я хочу чтобы был марк 2, а то у всех уже в городе марки, а я один как лошара<br>- ну тебе-то просто хочется, а мне... (вот тут внимание!!!!) НЕОБХОДИМО.<br><br>Кемп:<br>хорошо, что ты не сказал, что ты им еще и деньги зарабатываешь, а то она бы тебе какую-нибудь альтернативу с шубой придумала]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">66fab6cb65e11c7de896d7c6840095b9a90bd70ed8d49f8fb7adc0adb9b6a43c</guid>
+ <link>http://bash.org.ru/quote/414930</link>
+ <title>Цитата #414930</title>
+ <pubDate>Tue, 27 Dec 2011 13:46:01 +0400</pubDate>
+ <description><![CDATA[ххх: Друг мне вчера рассказал. Он барменом работает в заведении. Почти в ночи к ни начали заламываться два пьяных в зюзю чувака и охрана их не пустила, так как заведение приличное. Эти два типа не нашли ничего умнее и вызвали полицию, те приехали, их самих же забрали и увезли!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">39b40cb066f0a9b64c53dbc67c1a521a1b3948a5b021efd4b1982753059aaee1</guid>
+ <link>http://bash.org.ru/quote/414929</link>
+ <title>Цитата #414929</title>
+ <pubDate>Tue, 27 Dec 2011 13:13:01 +0400</pubDate>
+ <description><![CDATA[xxx: я им звонил<br>xxx: нет у них времени на понедельник<br>yyy: печалька<br>xxx: это уже не печалька<br>xxx: это уже злостька, яростька и гневик]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">4f3b79bfba6994d73b3eb21530d98188f4830c26c4f8108a6d8120a4c0b5e8fc</guid>
+ <link>http://bash.org.ru/quote/414928</link>
+ <title>Цитата #414928</title>
+ <pubDate>Tue, 27 Dec 2011 12:46:01 +0400</pubDate>
+ <description><![CDATA[Комменты к статье &quot;Как освободиться из наручников-стяжек&quot;:<br>xxx: А вот интересно, если ты едешь в багажнике машины, что делать?<br>yyy: если ночью и в лес – то это просто плохая примета.<br>zzz: Во всём надо искать позитив! Я уверен, это будет последняя плохая примета в вашей жизни! :)]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">d3162ccb1c30aa3f654c0c6b368fa9e583c020dc3d04bcc07b6c5f02eeadaaeb</guid>
+ <link>http://bash.org.ru/quote/414927</link>
+ <title>Цитата #414927</title>
+ <pubDate>Tue, 27 Dec 2011 12:13:01 +0400</pubDate>
+ <description><![CDATA[zzz: Ну вот как объяснить иностранцу, почему вилка — лежит, тарелка — стоит, а птица — сидит?<br>xxx: Вот, кстати, ноутбук: когда закрыта крышка — лежит, а когда открыта — стоит…<br>yyy: Я кажется начинаю понимать, лежит — без толку, а стоит — во имя Великой Справедливости!<br>]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">69e05b82fc5a5028a65e0435a584a83ffaa44e9784c024fb30eda9b7d87f38ba</guid>
+ <link>http://bash.org.ru/quote/414926</link>
+ <title>Цитата #414926</title>
+ <pubDate>Tue, 27 Dec 2011 11:46:03 +0400</pubDate>
+ <description><![CDATA[Sovershenstvo: распечатала документ на 115 страниц. забирала из принтера. обожглась о бумагу :(<br>iNote: принтер жжот :D]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">caa3a31eca89b56e3669c9910f23564e1ee2bd2c67f0be5472e206496b688609</guid>
+ <link>http://bash.org.ru/quote/414925</link>
+ <title>Цитата #414925</title>
+ <pubDate>Tue, 27 Dec 2011 11:45:01 +0400</pubDate>
+ <description><![CDATA[Из обсуждения использования акустического датчика для включения компьютера хлопком в ладоши:<br>xxx: Был такой случай.<br>xxx: Приятель сделал акустический выключатель на освещение.<br>xxx: Доставал книги с полки, стоя на табурете.<br>xxx: Упала книга, свет потух, он оступился, сломал руку.<br>xxx: Свет загорелся.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">d3db54801b673716d6b41137bbf9ca64c62a04a1211bf43ea44876c411f88728</guid>
+ <link>http://bash.org.ru/quote/414924</link>
+ <title>Цитата #414924</title>
+ <pubDate>Tue, 27 Dec 2011 11:13:12 +0400</pubDate>
+ <description><![CDATA[Обсуждаем с мужем Скайрим:<br>- Мне одной кажется, что драуги кудахтают? &quot;Куд-ку-да&quot;, &quot;Куд-ку-дааааа&quot;<br>- Это еще что. Вчера скелет подходит ко мне и четко так: &quot;пас-порт&quot;.<br>- Суровые скелеты древнескайримских пограничников. Из всего, что лепечут, можно разобрать только &quot;паспорт&quot; и &quot;уходи&quot; )]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">6206e668575ef7364ca52bacdfc3d6b45da5ab80d4c69c0f1467269cec9ee6c4</guid>
+ <link>http://bash.org.ru/quote/414923</link>
+ <title>Цитата #414923</title>
+ <pubDate>Tue, 27 Dec 2011 11:12:01 +0400</pubDate>
+ <description><![CDATA[xxx: Устроил диверсию на работе - принёс ирис &quot;Кис-Кис&quot; (советский, железобетонный). <br>xxx: Теперь никто со мной не разговаривает. <br>xxx: ВООБЩЕ НИКТО НИ С КЕМ НЕ РАЗГОВАРИВАЕТ! )))]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">47c8ec43ac12036ac0528b4b4077f8d9f80a0fe8d4aa029f8a39b7b9d4327b6f</guid>
+ <link>http://bash.org.ru/quote/414922</link>
+ <title>Цитата #414922</title>
+ <pubDate>Tue, 27 Dec 2011 10:45:34 +0400</pubDate>
+ <description><![CDATA[ххх: Я готовлюсь к зачету, только очень обдуманно. Со стороны это выглядит, будто я примеряю кирзачи]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">7871bd6a1b62f062468316e82234015b27a0c448d21c39120579d4c66c1b3367</guid>
+ <link>http://bash.org.ru/quote/414921</link>
+ <title>Цитата #414921</title>
+ <pubDate>Tue, 27 Dec 2011 10:45:01 +0400</pubDate>
+ <description><![CDATA[xxx: Переехали в новый офис. Спустя три месяца обнаружили люк под ногами, а из щели свет горит. Думаем теперь - вскрывать, или не стоит.<br>yyy: Вы аккуратней там. А то посуточно дежурить заставят и циферки вводить.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">c5fcb5c4cf429099d6540943fd5f376998aee7e5ac90409e8afc3e6a61ef177f</guid>
+ <link>http://bash.org.ru/quote/414920</link>
+ <title>Цитата #414920</title>
+ <pubDate>Tue, 27 Dec 2011 10:13:01 +0400</pubDate>
+ <description><![CDATA[MG: Мама моей мамы сказала моей маме: твою ж мать за ногу! И упала.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">72838435dc732ed7410037dd17b0e38588ac91999f5f195421621a8355ded16e</guid>
+ <link>http://bash.org.ru/quote/414919</link>
+ <title>Цитата #414919</title>
+ <pubDate>Tue, 27 Dec 2011 09:45:45 +0400</pubDate>
+ <description><![CDATA[Seryozha:<br>розовый уже не модно в этом сезоне<br>стоял на остановке<br>проехал мимо розовый лимузин<br>одна фифа другой сказала, что это безвкусица<br>и это вообще уебище<br>ну и потом щемились со мной в автобус]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">7b098f0d541bdc4ac0f90634a82e781d38e174ef380aa56ff6c94e69734fcde8</guid>
+ <link>http://bash.org.ru/quote/414918</link>
+ <title>Цитата #414918</title>
+ <pubDate>Tue, 27 Dec 2011 09:44:43 +0400</pubDate>
+ <description><![CDATA[Worontzoff: Избирательные участки будут оснащены камерами, куда будут помещать наблюдателей во время подсчета бюллетеней.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">5af15998f29f5f063b9ce01b54dc8d3f0b73bb7d3f877edcc5eaa7ff8f71013b</guid>
+ <link>http://bash.org.ru/quote/414917</link>
+ <title>Цитата #414917</title>
+ <pubDate>Tue, 27 Dec 2011 09:44:01 +0400</pubDate>
+ <description><![CDATA[ххх: У нас в два часа ночи пришествие Винни Пуха<br>ууу: В смысле? Мама пришла?<br>ххх: Не, Коля мед в холодильнике нашел. Ходит по квартире, нежно прижимая к себе банку. Я сегодня Пятачок]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">b5a66cb535552b46159d467911174f1e4aac941c8c1d891a62619a8cdb00a3ea</guid>
+ <link>http://bash.org.ru/quote/414916</link>
+ <title>Цитата #414916</title>
+ <pubDate>Tue, 27 Dec 2011 09:13:02 +0400</pubDate>
+ <description><![CDATA[(разговор о &quot;Лебедином Озере&quot;)<br>xxx: может быть, ты и сюжет помнишь?<br>yyy: очень смутно. Я совсем маленькая была, когда его в последний раз показывали...]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">9e007ee3d9984de85c727f6885f913891b11676f10b053ba8a51bec6fba0e23c</guid>
+ <link>http://bash.org.ru/quote/414915</link>
+ <title>Цитата #414915</title>
+ <pubDate>Tue, 27 Dec 2011 08:46:11 +0400</pubDate>
+ <description><![CDATA[xxx: привет<br>xxx: как служба?<br>yyy: как у служебной собаки<br>yyy: целый день спасаю мир, а вечером обещали покормить]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">3dc9ddc2fad185181993315c5c3a404405ab704423d3c24bd9213dcb23bad2eb</guid>
+ <link>http://bash.org.ru/quote/414914</link>
+ <title>Цитата #414914</title>
+ <pubDate>Tue, 27 Dec 2011 08:45:01 +0400</pubDate>
+ <description><![CDATA[ххх: нет, я скорее пойду убивать, чем красть<br>ууу: странная мораль, что так?<br>ххх: я человек честный, а потому злой]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">61e793991c5dea07ea5a5afa2bbc899e49c23d8a0d8a1f48918915129a13a35c</guid>
+ <link>http://bash.org.ru/quote/414913</link>
+ <title>Цитата #414913</title>
+ <pubDate>Tue, 27 Dec 2011 08:12:04 +0400</pubDate>
+ <description><![CDATA[Речь об аудионаркотиках:<br><br>ххх: Да фигня это всё!<br>yyy: Ну почему фигня, есть же звуки, которые как-то воздействуют на психику человека...<br>ххх: Да, на меня звук дрели так воздействует! Сразу хочется пойти и убить кого-нибудь!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">ed2932ac0768ceb5ec1a155d4b039fb2cba050296935d7852baccb238ada1819</guid>
+ <link>http://bash.org.ru/quote/414912</link>
+ <title>Цитата #414912</title>
+ <pubDate>Tue, 27 Dec 2011 08:11:31 +0400</pubDate>
+ <description><![CDATA[&lt;xxx&gt; готовили обед, полез в холодильник<br>&lt;xxx&gt; оказывается, вчера я невольно купил продуктовый набор &quot;Злые птицы&quot;: ноги куриные, грудка индейки, свиные эскалопы]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">1989a43d3a03de416d16788589caaa318ece611245b328df9b1567c13205cf70</guid>
+ <link>http://bash.org.ru/quote/414911</link>
+ <title>Цитата #414911</title>
+ <pubDate>Tue, 27 Dec 2011 08:11:01 +0400</pubDate>
+ <description><![CDATA[xxx: скользко на улице, даже собака гулять не хочет<br>yyy: ей-то что, у неё ж полный привод]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">c207fd198261176146047e54ccfff9058582e311ab402e32dfe67837c3e61e64</guid>
+ <link>http://bash.org.ru/quote/414910</link>
+ <title>Цитата #414910</title>
+ <pubDate>Mon, 26 Dec 2011 13:12:49 +0400</pubDate>
+ <description><![CDATA[Мама, купившая своему ребенку чехол к мобильному телефону, принесла его в магазин, чтобы вернуть продавцу.<br><br>П: На что жалуетесь?<br>М: Ребенок отказывается пользоваться чехлом.<br>П: Почему? Что не устраивает?<br>М: Мы заказывали чехол с человеком-пауком. На чехле надпись SPIDER-MAN. Так вот, когда застегиваем молнию, становится не видно букву S.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">245f34c6c6da77a68ba258f717177e3ecb27865bd7cd72c5966a9bae3d68cdab</guid>
+ <link>http://bash.org.ru/quote/414909</link>
+ <title>Цитата #414909</title>
+ <pubDate>Mon, 26 Dec 2011 13:11:56 +0400</pubDate>
+ <description><![CDATA[xxx: Дай фломастер, палец покрасить!<br>yyy: Зачем?<br>xxx: Иду в гости, а у меня носок дырявый!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">b9674cdf642593a5c193c3262031513822c50bcb950170cc07aadfb7fddc2649</guid>
+ <link>http://bash.org.ru/quote/414908</link>
+ <title>Цитата #414908</title>
+ <pubDate>Mon, 26 Dec 2011 13:11:02 +0400</pubDate>
+ <description><![CDATA[* В чат входит Вазелин.<br>Вазелин: студенты, я пришел<br>Вазелин: кому сколько?<br>Вазелин: пора бы уже заказывать]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">f5e384c1050a5d6df2cbe999fbae0e082deda5e89839ad0a913b490b3fada8c0</guid>
+ <link>http://bash.org.ru/quote/414907</link>
+ <title>Цитата #414907</title>
+ <pubDate>Mon, 26 Dec 2011 12:46:14 +0400</pubDate>
+ <description><![CDATA[ххх: гуляли с ребенком в парке, кормили уточек<br>ххх: сначала их было несколько штук, потом подплыли еще, некоторые пикировали с воздуха)))<br>ххх: приличное количество собралось, в общем, некоторые вылезли на берег и подошли к нам почти вплотную<br>ххх: в какой-то момент мне стало стремно, что булка кончается]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">71aba0126bc495b6efcd494e8b95c11b4e27fadb96f8fa31475db7aa85c7f1a4</guid>
+ <link>http://bash.org.ru/quote/414906</link>
+ <title>Цитата #414906</title>
+ <pubDate>Mon, 26 Dec 2011 12:45:14 +0400</pubDate>
+ <description><![CDATA[xxx: &quot;Если вы читали роман Жюля Верна или хотя бы смотрели фильм с одноимённым названием, то будете не то чтобы разочарованны, вы, мягко говоря, будете шокированы увиденным, начиная с первых секунд фильма&quot;<br><br>xxx: кто бы блять мог подумать, что именно так начинается рецензия к фильму Мушкетёры...]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">3d3b28ac59593143fe32ecbb4c5df048f39482f38d336d6dc4ad119ffbeea78b</guid>
+ <link>http://bash.org.ru/quote/414905</link>
+ <title>Цитата #414905</title>
+ <pubDate>Mon, 26 Dec 2011 12:44:01 +0400</pubDate>
+ <description><![CDATA[xxx: а ведущий программист - это такой программист, который может решить любую поставленную задачу его профиля самостоятельно<br>yyy: но не хочет )]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">2931790e946054e81789e63e91d5dc9237bf492d3f26c6d7bc530b59ef2672fe</guid>
+ <link>http://bash.org.ru/quote/414904</link>
+ <title>Цитата #414904</title>
+ <pubDate>Mon, 26 Dec 2011 12:13:01 +0400</pubDate>
+ <description><![CDATA[xxx: Погодите, на андроиде проходит авторизация по распознаванию лица? То есть, если мне набьют морду, я не смогу в скорую позвонить?<br>yyy: Боюсь, что набитие морды и отъём смартфона - события сильно скоррелированные, так что Ваша проблема несколько надуманна. :)]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">5ee6027cf4758aa3989a3552db60d21acfc4bce66518265e9137abc3ce1fc3c7</guid>
+ <link>http://bash.org.ru/quote/414903</link>
+ <title>Цитата #414903</title>
+ <pubDate>Mon, 26 Dec 2011 11:46:01 +0400</pubDate>
+ <description><![CDATA[leon:<br>Сегодня отвожу ребенка в школу, а там стенд новый повесили с фотографиями учителей. Озаглавлено гордо &quot;Сердце нашей школы!&quot;. Рядом с фотографией трудовика в берете, маркером стрелочка и надпись &quot;это печень&quot;.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">a47fdbea7602bfa4df71054ed3d391d00a1c0dd13f8adaa983bb5f93e5ac3d90</guid>
+ <link>http://bash.org.ru/quote/414902</link>
+ <title>Цитата #414902</title>
+ <pubDate>Mon, 26 Dec 2011 11:13:01 +0400</pubDate>
+ <description><![CDATA[xxx: безработный студент всем своим видом доказывает нам, что минимального размера оплаты труда не существует.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">bc8b51fdf44d63edc888ad063db2fa66d1ad92c48d999408fff00a8cbec8e4ae</guid>
+ <link>http://bash.org.ru/quote/414901</link>
+ <title>Цитата #414901</title>
+ <pubDate>Mon, 26 Dec 2011 10:46:12 +0400</pubDate>
+ <description><![CDATA[Psihodel: сегодня с утра пришла смс &quot;Мам кинь утром на мтс ххх-хх-хх-хх 950р. Мне не звони. Позже объясню.&quot; Через час мне жена сообщает, что она беременна. Теперь я понял, почему не надо звонить. Вот лет через 5 узнаю, зачем ему надо было 950р.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">e5174f709f5372c11eaf170b06efe25bf23fd3a65dbc9669e7b55b83ad598340</guid>
+ <link>http://bash.org.ru/quote/414900</link>
+ <title>Цитата #414900</title>
+ <pubDate>Mon, 26 Dec 2011 10:45:01 +0400</pubDate>
+ <description><![CDATA[xxx: Завтра встреча одногруппников. в 16:00 в Пабе на Таганке. Ну чего, ты будешь ?<br>yyy: Водку<br>yyy: Думаю я ответил сразу на два вопроса]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">0f5c7eaee411484a37e8071fb60030eb902f42a26969363233116d425faec446</guid>
+ <link>http://bash.org.ru/quote/414899</link>
+ <title>Цитата #414899</title>
+ <pubDate>Mon, 26 Dec 2011 10:12:34 +0400</pubDate>
+ <description><![CDATA[Настоящий радиолюбитель, открыв спичечный коробок и обнаружив там спички, смотрит на них С УДИВЛЕНИЕМ]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">1941999057f97da275dbaee167f5314de54a3de0f1ccc0f25c983cfe08845e71</guid>
+ <link>http://bash.org.ru/quote/414898</link>
+ <title>Цитата #414898</title>
+ <pubDate>Mon, 26 Dec 2011 10:12:01 +0400</pubDate>
+ <description><![CDATA[xxx: Если в вашей жизни постоянно происходит какая-то херня, то стоит задуматься, а не вы ли та самая херня.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">1493df9ec128867419e1c9e0f8adf1e7c73eaecba9ba81e51395778f2c599faf</guid>
+ <link>http://bash.org.ru/quote/414897</link>
+ <title>Цитата #414897</title>
+ <pubDate>Mon, 26 Dec 2011 09:46:15 +0400</pubDate>
+ <description><![CDATA[ххх: плохая это идея, с детскими домашними праздниками.<br>ууу: да почему? у меня знакомые этим каждые праздники занимаются. вполне неплохо для подработки, весело + сразу деньги в кармане.<br>ххх: пару лет назад мы с подругой тоже раздобыли новогодних костюмов, написали веселый сценарий и развеслили объявления: &quot;Волшебное новогоднее приключение от сестричек-Снегурочек в вашем доме&quot;.<br>ххх: ах вы мои неиспорченные!<br>ууу: ага, все правильно понял.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">507045f7af9d1dbc586b1ea528ecc9edb09ea5a1f35dab1141afc0dee491c7f2</guid>
+ <link>http://bash.org.ru/quote/414896</link>
+ <title>Цитата #414896</title>
+ <pubDate>Mon, 26 Dec 2011 09:45:01 +0400</pubDate>
+ <description><![CDATA[CKuB: ЗАЯ, бля! Переложить все говно на мою полку - это не то, что я имел в виду, прося навести порядок у себя на полке!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">e4f30a21e7ffa737cc164ea71ddf1fe24a2c87b269a1b47db1dbf591ebe3e843</guid>
+ <link>http://bash.org.ru/quote/414895</link>
+ <title>Цитата #414895</title>
+ <pubDate>Mon, 26 Dec 2011 09:12:45 +0400</pubDate>
+ <description><![CDATA[xxx: Админская примета.<br>xxx: Если 12-летний сын начальника идет в серверную - к большой беде.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">0ac1bcd3e77c115764edf2fef78568d7e88f0dcfa2830ebff7a4a67ca246192b</guid>
+ <link>http://bash.org.ru/quote/414894</link>
+ <title>Цитата #414894</title>
+ <pubDate>Mon, 26 Dec 2011 09:11:52 +0400</pubDate>
+ <description><![CDATA[Vegyja: романтика - чем ее меньше, тем лучше. если парень только и делает, что страдает такой фигней... вопрос возникает: а мужчина ли он?<br>Telecantrelem: А если предложить девушке бутерброд с колбасой - это романтика?<br>1143r: Telecantrelem, в определенных обстоятельствах это очень даже романтично. Например, Она выпила стакан самогону, а закусить нечем. А тут ты с бутером. Опа! На, ешь!]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">0b0d1ae0708037d49d4edd71c8e1d7a488907c379787b7827be44ba7adab6cef</guid>
+ <link>http://bash.org.ru/quote/414893</link>
+ <title>Цитата #414893</title>
+ <pubDate>Mon, 26 Dec 2011 09:11:01 +0400</pubDate>
+ <description><![CDATA[Из объяснительной записки:<br><br>12.12 на складе №4 был разгружен ламинат &quot;...&quot; с большим количеством брака. Пачки были отсортированы мной и подписаны, хорошие пачки &quot;Х&quot;, а плохие пачки &quot;П&quot;. При возврате товара поставщику, начальник склада ошибочно посчитал, что &quot;Х&quot; означает &quot;хуёвые&quot;, а &quot;П&quot; означает &quot;пиздатые&quot;, что в корне меняло ситуацию. Грузчики его поддержали и на возврат был отгружен качественный товар. Виновным в данном инциденте себя не признаю, услуги транспортной компании оплачивать отказываюсь.]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">4caeec3b83a23c4ef7e6822f1b9151c62dd719538f9719fd9dc49079edf12869</guid>
+ <link>http://bash.org.ru/quote/414892</link>
+ <title>Цитата #414892</title>
+ <pubDate>Mon, 26 Dec 2011 08:46:01 +0400</pubDate>
+ <description><![CDATA[Лена: что делать, если кот спит, я одна дома, а на кухне грохот?<br>Олег: кинь туда кота)]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">533d63288a28594dd6858f5eb212c9fd62c95da02ef6c532902585a525f78b2e</guid>
+ <link>http://bash.org.ru/quote/414891</link>
+ <title>Цитата #414891</title>
+ <pubDate>Mon, 26 Dec 2011 08:13:01 +0400</pubDate>
+ <description><![CDATA[он: Расскажи мне сказку<br>она: Жила-была некая функция эф от икс, и была она дифференцируема на всей эпсилон-окрестности некой точки икс нулевое<br>она: У меня численные методы )<br>она: Извини )]]></description>
+ </item>
+ <item>
+ <guid isPermaLink="false">92cf655d26cbe5d10b1af532ab4abb491a0d74ae9759cb81cd6dd4bb84a1d2bc</guid>
+ <link>http://bash.org.ru/quote/414890</link>
+ <title>Цитата #414890</title>
+ <pubDate>Sun, 25 Dec 2011 09:13:01 +0400</pubDate>
+ <description><![CDATA[смс из очереди к врачу<br><br>ххх: Мама, за час приняли только двух больных и они до сих пор там. передо мной 12 злых и опасных бабушек, которые уже успели закатить два скандала с применением двери и грубой физической силы тем, кто пытался пройти без очереди. Подчёркиваю: ПЫТАЛСЯ! Мне есть смысл сидеть дальше?]]></description>
+ </item>
+ </channel>
+</rss> \ No newline at end of file
diff --git a/protocols/NewsAggregator/docs/ToDo.txt b/protocols/NewsAggregator/docs/ToDo.txt
new file mode 100644
index 0000000000..09484b7932
--- /dev/null
+++ b/protocols/NewsAggregator/docs/ToDo.txt
@@ -0,0 +1,11 @@
+Парсить xml
+экспорт\импорт
+автоимпорт из файла
+авторизация
+замена всего html'ного
+
+xml parse
+contacts export\import
+autoimport from file service
+authorization
+replace all html to text \ No newline at end of file
diff --git a/protocols/NewsAggregator/docs/subscriptions_test.xml b/protocols/NewsAggregator/docs/subscriptions_test.xml
new file mode 100644
index 0000000000..bae46438dd
--- /dev/null
+++ b/protocols/NewsAggregator/docs/subscriptions_test.xml
@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<opml version="1.0">
+ <head>
+ <title>BasiL: подписки в Google Reader</title>
+ </head>
+ <body>
+ <outline text="ithappens" title="ithappens" type="rss"
+ xmlUrl="http://ithappens.ru/rss" htmlUrl="http://ithappens.ru/"/>
+ <outline title="Computerra" text="Computerra">
+ <outline title="My_Test" text="My_Test">
+ <outline text="bash" title="bash" type="rss"
+ xmlUrl="http://bash.im/rss" htmlUrl="http://bash.im/"/>
+ </outline>
+ <outline text="inside" title="inside" type="rss"
+ xmlUrl="http://www.ctinside.com/feeds/posts/default" htmlUrl="http://www.ctinside.com/"/>
+ <outline text="Компьюлента" title="Компьюлента" type="rss"
+ xmlUrl="http://www.compulenta.ru/rss.xml" htmlUrl="http://www.compulenta.ru"/>
+ <outline text="Статьи Компьютерры"
+ title="Статьи Компьютерры" type="rss"
+ xmlUrl="http://www.computerra.ru/rss.xml" htmlUrl="http://www.computerra.ru"/>
+ </outline>
+ <outline title="Soft" text="Soft">
+ <outline
+ text="Downloads for project cm9-wildfire-s on Google Code"
+ title="Downloads for project cm9-wildfire-s on Google Code"
+ type="rss"
+ xmlUrl="https://code.google.com/feeds/p/cm9-wildfire-s/downloads/basic" htmlUrl="http://code.google.com/p/cm9-wildfire-s/downloads/list"/>
+ <outline text="Downloads for project uawks on Google Code"
+ title="Downloads for project uawks on Google Code"
+ type="rss"
+ xmlUrl="http://code.google.com/feeds/p/uawks/downloads/basic" htmlUrl="http://code.google.com/p/uawks/downloads/list"/>
+ <outline
+ text="Issue updates for project uawks on Google Code"
+ title="Issue updates for project uawks on Google Code"
+ type="rss"
+ xmlUrl="http://code.google.com/feeds/p/uawks/issueupdates/basic" htmlUrl="http://code.google.com/p/uawks/issues/list"/>
+ <outline
+ text="Mercurial commits to project uawks on Google Code"
+ title="Mercurial commits to project uawks on Google Code"
+ type="rss"
+ xmlUrl="http://code.google.com/feeds/p/uawks/hgchanges/basic" htmlUrl="http://code.google.com/p/uawks/source/list"/>
+ <outline text="Punk" title="Punk" type="rss"
+ xmlUrl="http://www.punksoftware.com/rss" htmlUrl="http://punklabs.com/rss"/>
+ <outline text="Tomato by Shibby" title="Tomato by Shibby"
+ type="rss" xmlUrl="http://tomato.groov.pl/?feed=rss2" htmlUrl="http://tomato.groov.pl"/>
+ <outline text="TOR" title="TOR" type="rss"
+ xmlUrl="http://rss.gmane.org/gmane.network.onion-routing.announce" htmlUrl="http://permalink.gmane.org/gmane.network.onion-routing.announce"/>
+ <outline text="VideoLAN" title="VideoLAN" type="rss"
+ xmlUrl="http://www.videolan.org/videolan-news.rss" htmlUrl="http://www.videolan.org/"/>
+ </outline>
+ <outline title="Miranda" text="Miranda">
+ <outline text="Dev Blog" title="Dev Blog" type="rss"
+ xmlUrl="http://feeds.miranda-im.org/mirandadevjournal" htmlUrl="http://www.miranda-im.org"/>
+ <outline text="FLNew" title="FLNew" type="rss"
+ xmlUrl="http://feeds.miranda-im.org/mirandalast10add" htmlUrl="http://addons.miranda-im.org"/>
+ <outline text="FLupd" title="FLupd" type="rss"
+ xmlUrl="http://feeds.miranda-im.org/mirandalast10upd" htmlUrl="http://addons.miranda-im.org"/>
+ <outline text="mir-rl project updates - Google Code"
+ title="mir-rl project updates - Google Code" type="rss"
+ xmlUrl="http://code.google.com/feeds/p/mir-rl/updates/basic" htmlUrl="http://code.google.com/p/mir-rl/updates/list"/>
+ <outline text="Miranda IM" title="Miranda IM" type="rss"
+ xmlUrl="http://feeds.feedburner.com/mirandaannouncements" htmlUrl="http://www.miranda-im.org"/>
+ <outline text="Miranda IM Community"
+ title="Miranda IM Community" type="rss"
+ xmlUrl="http://community.livejournal.com/ru_mirandaim/data/rss" htmlUrl="http://ru-mirandaim.livejournal.com/"/>
+ <outline
+ text="Miranda-Planet - ваша планета Miranda IM ( билды, сборки, скины, плагины, русификация, WiKi, Форум )"
+ title="Miranda-Planet - ваша планета Miranda IM ( билды, сборки, скины, плагины, русификация, WiKi, Форум )"
+ type="rss" xmlUrl="http://miranda-planet.com/rss.xml" htmlUrl="http://miranda-planet.com/"/>
+ <outline text="ruCommunity" title="ruCommunity" type="rss"
+ xmlUrl="http://forum.miranda.im/external.php?type=RSS2" htmlUrl="http://forum.miranda.im"/>
+ </outline>
+ <outline title="Habr" text="Habr">
+ <outline text="Android" title="Android" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/android/" htmlUrl="http://habrahabr.ru/rss/hub/android/"/>
+ <outline text="Design" title="Design" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/design/" htmlUrl="http://habrahabr.ru/rss/hub/design/"/>
+ <outline text="DSLR" title="DSLR" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/dslr/" htmlUrl="http://habrahabr.ru/rss/blog/dslr/"/>
+ <outline text="Future" title="Future" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/the_future_is_here/" htmlUrl="http://habrahabr.ru/rss/hub/the_future_is_here/"/>
+ <outline text="Google" title="Google" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/google/" htmlUrl="http://habrahabr.ru/rss/hub/google/"/>
+ <outline text="Hardware" title="Hardware" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/hardware/" htmlUrl="http://habrahabr.ru/rss/hub/hardware/"/>
+ <outline text="IM" title="IM" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/im/" htmlUrl="http://habrahabr.ru/rss/hub/im/"/>
+ <outline text="Jabber" title="Jabber" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/jabber/" htmlUrl="http://habrahabr.ru/rss/blogs/jabber/"/>
+ <outline text="Miranda" title="Miranda" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/miranda/" htmlUrl="http://habrahabr.ru/rss/blogs/miranda/"/>
+ <outline text="Netbook" title="Netbook" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/netbook/" htmlUrl="http://habrahabr.ru/rss/hub/netbook/"/>
+ <outline text="OldThings" title="OldThings" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/retro/" htmlUrl="http://habrahabr.ru/rss/blogs/retro/"/>
+ <outline text="Robots" title="Robots" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/robot/" htmlUrl="http://habrahabr.ru/rss/hub/robot/"/>
+ <outline text="sciense" title="sciense" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/popular_science/" htmlUrl="http://habrahabr.ru/rss/hub/popular_science/"/>
+ <outline text="TC" title="TC" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/totalcmd/" htmlUrl="http://habrahabr.ru/rss/blogs/totalcmd/"/>
+ <outline text="Telecom" title="Telecom" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/telecom/" htmlUrl="http://habrahabr.ru/rss/hub/telecom/"/>
+ <outline text="Win7" title="Win7" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/windows7/" htmlUrl="http://habrahabr.ru/rss/blogs/windows7/"/>
+ <outline text="Хабрахабр / Биотехнологии / Захабренные"
+ title="Хабрахабр / Биотехнологии / Захабренные"
+ type="rss"
+ xmlUrl="http://habrahabr.ru/rss/blogs/biotech/" htmlUrl="http://habrahabr.ru/rss/hub/biotech/"/>
+ <outline text="Хабрахабр: Метки / wzor.net"
+ title="Хабрахабр: Метки / wzor.net" type="rss"
+ xmlUrl="http://habrahabr.ru/rss/tag/wzor.net/" htmlUrl="http://habrahabr.ru/rss/tag/wzor.net/"/>
+ </outline>
+ <outline title="News" text="News">
+ <outline text="2КОМ (новости)" title="2КОМ (новости)"
+ type="rss"
+ xmlUrl="http://www.2kom.ru/home/news/-rss.xml" htmlUrl="http://www.2kom.ru/home/news.html"/>
+ <outline text="4PDA" title="4PDA" type="rss"
+ xmlUrl="http://4pda.ru/feed/" htmlUrl="http://4pda.ru/"/>
+ <outline text="FotoTips.ru" title="FotoTips.ru" type="rss"
+ xmlUrl="http://feeds.feedburner.com/fototipsru" htmlUrl="http://fototips.ru"/>
+ <outline text="LifeHack.ru" title="LifeHack.ru" type="rss"
+ xmlUrl="http://www.lifehack.ru/rss/" htmlUrl="http://lifehack.ru"/>
+ <outline text="MForum.ru" title="MForum.ru" type="rss"
+ xmlUrl="http://www.mforum.ru/rss/news.xml" htmlUrl="http://www.mforum.ru/"/>
+ <outline text="Overclockers.ru" title="Overclockers.ru"
+ type="rss"
+ xmlUrl="http://www.overclockers.ru/rss/all.rss" htmlUrl="http://www.overclockers.ru"/>
+ <outline text="revolver.ru" title="revolver.ru" type="rss"
+ xmlUrl="http://revolver.ru/rss" htmlUrl="http://revolver.ru/"/>
+ <outline text="Самый сок!" title="Самый сок!" type="rss"
+ xmlUrl="http://ibigdan.livejournal.com/data/rss" htmlUrl="http://ibigdan.livejournal.com/"/>
+ <outline text="Танки Онлайн" title="Танки Онлайн" type="rss"
+ xmlUrl="http://blog.tankionline.com/feed/" htmlUrl="http://news.tankionline.com"/>
+ <outline text="Фергана.Ру" title="Фергана.Ру" type="rss"
+ xmlUrl="http://news.ferghana.ru/news.xml" htmlUrl="http://www.fergananews.com"/>
+ </outline>
+ <outline title="TC" text="TC">
+ <outline text="en.totalcmd.pl" title="en.totalcmd.pl"
+ type="rss" xmlUrl="http://en.totalcmd.pl/rss" htmlUrl="http://en.totalcmd.pl"/>
+ <outline text="tc" title="tc" type="rss"
+ xmlUrl="http://wincmd.ru/rss.xml" htmlUrl="http://wincmd.ru"/>
+ </outline>
+ <outline title="Science" text="Science">
+ <outline text="Astronet" title="Astronet" type="rss"
+ xmlUrl="http://www.astronet.ru/db/rss.xml" htmlUrl="http://www.astronet.ru/"/>
+ <outline text="COPAH.info - Наука. Сибирь. Общество"
+ title="COPAH.info - Наука. Сибирь. Общество" type="rss"
+ xmlUrl="http://www.copah.info/rss" htmlUrl="http://www.copah.info/rss"/>
+ <outline text="LHC" title="LHC" type="rss"
+ xmlUrl="http://fulltextrssfeed.com/elementy.ru/rss/news/LHC" htmlUrl="http://elementy.ru/LHC/news"/>
+ <outline text="Membrana.ru" title="Membrana.ru" type="rss"
+ xmlUrl="http://ftr.fivefilters.org/makefulltextfeed.php?url=http%3A%2F%2Fwww.membrana.ru%2Fexport%2Frss.xml&amp;max=1" htmlUrl="http://www.membrana.ru"/>
+ <outline text="Иванов" title="Иванов" type="rss"
+ xmlUrl="http://igorivanov.blogspot.com/feeds/posts/default" htmlUrl="http://igorivanov.blogspot.com/"/>
+ <outline text="НаукаИжизнь" title="НаукаИжизнь" type="rss"
+ xmlUrl="http://fulltextrssfeed.com/www.nkj.ru/rss/iblock_rss_31.xml" htmlUrl="http://www.nkj.ru"/>
+ <outline text="Элементы" title="Элементы" type="rss"
+ xmlUrl="http://fulltextrssfeed.com/elementy.ru/rss/news" htmlUrl="http://elementy.ru/"/>
+ </outline>
+ <outline title="Moviez" text="Moviez">
+ <outline text="Twitter / kuraj_bambey"
+ title="Twitter / kuraj_bambey" type="rss"
+ xmlUrl="http://twitter.com/statuses/user_timeline/44353505.rss" htmlUrl="http://twitter.com/kuraj_bambey"/>
+ <outline text="Мосенька" title="Мосенька" type="rss"
+ xmlUrl="http://feed.rutracker.org/atom/u/0/26/3796626.atom" htmlUrl="http://rutracker.org/forum/profile.php?mode=viewprofile&amp;u=3796626"/>
+ </outline>
+ </body>
+</opml>
diff --git a/protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj b/protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj
new file mode 100644
index 0000000000..1183249dd0
--- /dev/null
+++ b/protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>Proto_NewsAggregator</ProjectName>
+ <ProjectGuid>{B97882DC-7462-41DB-A390-BDFCE5295265}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\..\build\vc.common\icons.props" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj.filters b/protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj.filters
new file mode 100644
index 0000000000..28f81e7f1b
--- /dev/null
+++ b/protocols/NewsAggregator/proto_newsaggregator/Proto_NewsAggregator.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/protocols/NewsAggregator/proto_newsaggregator/res/Offline.ico b/protocols/NewsAggregator/proto_newsaggregator/res/Offline.ico
new file mode 100644
index 0000000000..b4fba290e7
--- /dev/null
+++ b/protocols/NewsAggregator/proto_newsaggregator/res/Offline.ico
Binary files differ
diff --git a/protocols/NewsAggregator/proto_newsaggregator/res/Online.ico b/protocols/NewsAggregator/proto_newsaggregator/res/Online.ico
new file mode 100644
index 0000000000..75c9ff1aa3
--- /dev/null
+++ b/protocols/NewsAggregator/proto_newsaggregator/res/Online.ico
Binary files differ
diff --git a/protocols/NewsAggregator/proto_newsaggregator/res/Proto_NewsAggregator.rc b/protocols/NewsAggregator/proto_newsaggregator/res/Proto_NewsAggregator.rc
new file mode 100644
index 0000000000..814c9e4f26
--- /dev/null
+++ b/protocols/NewsAggregator/proto_newsaggregator/res/Proto_NewsAggregator.rc
@@ -0,0 +1,70 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian (Russia) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "..\\src\\resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_ICON1 ICON "Offline.ico"
+IDI_ICON2 ICON "Online.ico"
+#endif // Russian (Russia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/NewsAggregator/proto_newsaggregator/src/resource.h b/protocols/NewsAggregator/proto_newsaggregator/src/resource.h
new file mode 100644
index 0000000000..38085445db
--- /dev/null
+++ b/protocols/NewsAggregator/proto_newsaggregator/src/resource.h
@@ -0,0 +1,17 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Proto_NewsAggr.rc
+//
+#define IDI_ICON1 105
+#define IDI_ICON2 104
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 103
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif