summaryrefslogtreecommitdiff
path: root/protocols/JabberG/src
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/JabberG/src')
-rw-r--r--protocols/JabberG/src/jabber.cpp2
-rw-r--r--protocols/JabberG/src/jabber_adhoc.cpp2
-rw-r--r--protocols/JabberG/src/jabber_agent.cpp2
-rw-r--r--protocols/JabberG/src/jabber_api.cpp2
-rw-r--r--protocols/JabberG/src/jabber_archive.cpp2
-rw-r--r--protocols/JabberG/src/jabber_bookmarks.cpp2
-rw-r--r--protocols/JabberG/src/jabber_byte.cpp2
-rw-r--r--protocols/JabberG/src/jabber_byte.h2
-rw-r--r--protocols/JabberG/src/jabber_caps.cpp2
-rw-r--r--protocols/JabberG/src/jabber_caps.h2
-rw-r--r--protocols/JabberG/src/jabber_captcha.cpp2
-rw-r--r--protocols/JabberG/src/jabber_chat.cpp2
-rw-r--r--protocols/JabberG/src/jabber_console.cpp2
-rw-r--r--protocols/JabberG/src/jabber_disco.cpp2
-rw-r--r--protocols/JabberG/src/jabber_disco.h2
-rw-r--r--protocols/JabberG/src/jabber_events.cpp2
-rw-r--r--protocols/JabberG/src/jabber_file.cpp2
-rw-r--r--protocols/JabberG/src/jabber_form.cpp2
-rw-r--r--protocols/JabberG/src/jabber_ft.cpp2
-rw-r--r--protocols/JabberG/src/jabber_groupchat.cpp2
-rw-r--r--protocols/JabberG/src/jabber_ibb.cpp2
-rw-r--r--protocols/JabberG/src/jabber_ibb.h2
-rw-r--r--protocols/JabberG/src/jabber_icolib.cpp2
-rw-r--r--protocols/JabberG/src/jabber_icolib.h2
-rw-r--r--protocols/JabberG/src/jabber_iq.cpp2
-rw-r--r--protocols/JabberG/src/jabber_iq.h2
-rw-r--r--protocols/JabberG/src/jabber_iq_handlers.cpp2
-rw-r--r--protocols/JabberG/src/jabber_iqid.cpp2
-rw-r--r--protocols/JabberG/src/jabber_iqid_muc.cpp2
-rw-r--r--protocols/JabberG/src/jabber_libstr.cpp2
-rw-r--r--protocols/JabberG/src/jabber_list.cpp2
-rw-r--r--protocols/JabberG/src/jabber_list.h2
-rw-r--r--protocols/JabberG/src/jabber_mam.cpp320
-rw-r--r--protocols/JabberG/src/jabber_menu.cpp2
-rw-r--r--protocols/JabberG/src/jabber_message_handlers.cpp2
-rw-r--r--protocols/JabberG/src/jabber_message_manager.cpp2
-rw-r--r--protocols/JabberG/src/jabber_message_manager.h2
-rw-r--r--protocols/JabberG/src/jabber_misc.cpp2
-rw-r--r--protocols/JabberG/src/jabber_notes.cpp2
-rw-r--r--protocols/JabberG/src/jabber_notes.h2
-rw-r--r--protocols/JabberG/src/jabber_omemo.cpp2
-rw-r--r--protocols/JabberG/src/jabber_omemo.h2
-rw-r--r--protocols/JabberG/src/jabber_opt.cpp2
-rw-r--r--protocols/JabberG/src/jabber_password.cpp2
-rw-r--r--protocols/JabberG/src/jabber_presence_manager.cpp2
-rw-r--r--protocols/JabberG/src/jabber_presence_manager.h2
-rw-r--r--protocols/JabberG/src/jabber_privacy.cpp2
-rw-r--r--protocols/JabberG/src/jabber_privacy.h2
-rw-r--r--protocols/JabberG/src/jabber_proto.cpp2
-rw-r--r--protocols/JabberG/src/jabber_proto.h2
-rw-r--r--protocols/JabberG/src/jabber_rc.cpp2
-rw-r--r--protocols/JabberG/src/jabber_rc.h2
-rw-r--r--protocols/JabberG/src/jabber_roster.cpp1102
-rw-r--r--protocols/JabberG/src/jabber_search.cpp1530
-rw-r--r--protocols/JabberG/src/jabber_search.h2
-rw-r--r--protocols/JabberG/src/jabber_secur.cpp2
-rw-r--r--protocols/JabberG/src/jabber_secur.h2
-rw-r--r--protocols/JabberG/src/jabber_send_manager.cpp2
-rw-r--r--protocols/JabberG/src/jabber_send_manager.h2
-rw-r--r--protocols/JabberG/src/jabber_strm_mgmt.cpp2
-rw-r--r--protocols/JabberG/src/jabber_strm_mgmt.h2
-rw-r--r--protocols/JabberG/src/jabber_svc.cpp2
-rw-r--r--protocols/JabberG/src/jabber_thread.cpp2
-rw-r--r--protocols/JabberG/src/jabber_treelist.cpp2
-rw-r--r--protocols/JabberG/src/jabber_userinfo.cpp1824
-rw-r--r--protocols/JabberG/src/jabber_util.cpp2
-rw-r--r--protocols/JabberG/src/jabber_vcard.cpp2
-rw-r--r--protocols/JabberG/src/jabber_xml.cpp2
-rw-r--r--protocols/JabberG/src/jabber_xml.h2
-rw-r--r--protocols/JabberG/src/jabber_xstatus.cpp2
-rw-r--r--protocols/JabberG/src/jabber_xstatus.h2
-rw-r--r--protocols/JabberG/src/jabber_zstream.cpp2
-rw-r--r--protocols/JabberG/src/stdafx.cxx2
-rw-r--r--protocols/JabberG/src/stdafx.h2
-rw-r--r--protocols/JabberG/src/version.h2
75 files changed, 2459 insertions, 2459 deletions
diff --git a/protocols/JabberG/src/jabber.cpp b/protocols/JabberG/src/jabber.cpp
index c0fdff4ccd..50dac791a6 100644
--- a/protocols/JabberG/src/jabber.cpp
+++ b/protocols/JabberG/src/jabber.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_adhoc.cpp b/protocols/JabberG/src/jabber_adhoc.cpp
index d5b6d429f1..1871262e16 100644
--- a/protocols/JabberG/src/jabber_adhoc.cpp
+++ b/protocols/JabberG/src/jabber_adhoc.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Artem Shpynov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
Module implements an XMPP protocol extension for reporting and executing ad-hoc,
human-oriented commands according to XEP-0050: Ad-Hoc Commands
diff --git a/protocols/JabberG/src/jabber_agent.cpp b/protocols/JabberG/src/jabber_agent.cpp
index a198827672..a8720b5a56 100644
--- a/protocols/JabberG/src/jabber_agent.cpp
+++ b/protocols/JabberG/src/jabber_agent.cpp
@@ -4,7 +4,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_api.cpp b/protocols/JabberG/src/jabber_api.cpp
index db750517f3..738e1bb439 100644
--- a/protocols/JabberG/src/jabber_api.cpp
+++ b/protocols/JabberG/src/jabber_api.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_archive.cpp b/protocols/JabberG/src/jabber_archive.cpp
index 97c76993ba..b60f98ac97 100644
--- a/protocols/JabberG/src/jabber_archive.cpp
+++ b/protocols/JabberG/src/jabber_archive.cpp
@@ -4,7 +4,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_bookmarks.cpp b/protocols/JabberG/src/jabber_bookmarks.cpp
index 0c9944677a..48cc195e17 100644
--- a/protocols/JabberG/src/jabber_bookmarks.cpp
+++ b/protocols/JabberG/src/jabber_bookmarks.cpp
@@ -3,7 +3,7 @@
Jabber Protocol Plugin for Miranda NG
Copyright (c) 2007 Michael Stepura, George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_byte.cpp b/protocols/JabberG/src/jabber_byte.cpp
index 685174347d..060b10ee6c 100644
--- a/protocols/JabberG/src/jabber_byte.cpp
+++ b/protocols/JabberG/src/jabber_byte.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_byte.h b/protocols/JabberG/src/jabber_byte.h
index 6e3f5b732b..5de0be588c 100644
--- a/protocols/JabberG/src/jabber_byte.h
+++ b/protocols/JabberG/src/jabber_byte.h
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_caps.cpp b/protocols/JabberG/src/jabber_caps.cpp
index e49f93d8a8..16ad003a75 100644
--- a/protocols/JabberG/src/jabber_caps.cpp
+++ b/protocols/JabberG/src/jabber_caps.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_caps.h b/protocols/JabberG/src/jabber_caps.h
index fc37993fb0..e8ceccf4a0 100644
--- a/protocols/JabberG/src/jabber_caps.h
+++ b/protocols/JabberG/src/jabber_caps.h
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_captcha.cpp b/protocols/JabberG/src/jabber_captcha.cpp
index 641c310395..c2cc8ec2eb 100644
--- a/protocols/JabberG/src/jabber_captcha.cpp
+++ b/protocols/JabberG/src/jabber_captcha.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_chat.cpp b/protocols/JabberG/src/jabber_chat.cpp
index a32591e576..90bf730ac4 100644
--- a/protocols/JabberG/src/jabber_chat.cpp
+++ b/protocols/JabberG/src/jabber_chat.cpp
@@ -4,7 +4,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_console.cpp b/protocols/JabberG/src/jabber_console.cpp
index 7f4ab9c19f..cbcfc0f19d 100644
--- a/protocols/JabberG/src/jabber_console.cpp
+++ b/protocols/JabberG/src/jabber_console.cpp
@@ -6,7 +6,7 @@ Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
Copyright (c) 2007 Victor Pavlychko
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_disco.cpp b/protocols/JabberG/src/jabber_disco.cpp
index cca24a8d29..50081898fd 100644
--- a/protocols/JabberG/src/jabber_disco.cpp
+++ b/protocols/JabberG/src/jabber_disco.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_disco.h b/protocols/JabberG/src/jabber_disco.h
index 48a01bfa93..5f3bd510df 100644
--- a/protocols/JabberG/src/jabber_disco.h
+++ b/protocols/JabberG/src/jabber_disco.h
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2005-07 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_events.cpp b/protocols/JabberG/src/jabber_events.cpp
index 043c438c95..da9f81c7bc 100644
--- a/protocols/JabberG/src/jabber_events.cpp
+++ b/protocols/JabberG/src/jabber_events.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_file.cpp b/protocols/JabberG/src/jabber_file.cpp
index b01b32f32a..f39cbbdf32 100644
--- a/protocols/JabberG/src/jabber_file.cpp
+++ b/protocols/JabberG/src/jabber_file.cpp
@@ -4,7 +4,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_form.cpp b/protocols/JabberG/src/jabber_form.cpp
index e4e51658ea..e85e91566a 100644
--- a/protocols/JabberG/src/jabber_form.cpp
+++ b/protocols/JabberG/src/jabber_form.cpp
@@ -4,7 +4,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_ft.cpp b/protocols/JabberG/src/jabber_ft.cpp
index 096351d713..0329d16747 100644
--- a/protocols/JabberG/src/jabber_ft.cpp
+++ b/protocols/JabberG/src/jabber_ft.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_groupchat.cpp b/protocols/JabberG/src/jabber_groupchat.cpp
index 7fd448657f..f4f3e6c008 100644
--- a/protocols/JabberG/src/jabber_groupchat.cpp
+++ b/protocols/JabberG/src/jabber_groupchat.cpp
@@ -4,7 +4,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_ibb.cpp b/protocols/JabberG/src/jabber_ibb.cpp
index 22d1f2e41e..67ba5ba2c9 100644
--- a/protocols/JabberG/src/jabber_ibb.cpp
+++ b/protocols/JabberG/src/jabber_ibb.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_ibb.h b/protocols/JabberG/src/jabber_ibb.h
index b96ae971f9..f620b52ba4 100644
--- a/protocols/JabberG/src/jabber_ibb.h
+++ b/protocols/JabberG/src/jabber_ibb.h
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_icolib.cpp b/protocols/JabberG/src/jabber_icolib.cpp
index 4fe3a7d96c..7e08277418 100644
--- a/protocols/JabberG/src/jabber_icolib.cpp
+++ b/protocols/JabberG/src/jabber_icolib.cpp
@@ -4,7 +4,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
Idea & portions of code by Artem Shpynov
diff --git a/protocols/JabberG/src/jabber_icolib.h b/protocols/JabberG/src/jabber_icolib.h
index 7d2c0b1ce2..9066560f1d 100644
--- a/protocols/JabberG/src/jabber_icolib.h
+++ b/protocols/JabberG/src/jabber_icolib.h
@@ -6,7 +6,7 @@ Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007-09 Maxim Mluhov
Copyright (c) 2007-09 Victor Pavlychko
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_iq.cpp b/protocols/JabberG/src/jabber_iq.cpp
index 9e1dc7dc20..850e755420 100644
--- a/protocols/JabberG/src/jabber_iq.cpp
+++ b/protocols/JabberG/src/jabber_iq.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_iq.h b/protocols/JabberG/src/jabber_iq.h
index 50694fc73e..01da599737 100644
--- a/protocols/JabberG/src/jabber_iq.h
+++ b/protocols/JabberG/src/jabber_iq.h
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_iq_handlers.cpp b/protocols/JabberG/src/jabber_iq_handlers.cpp
index d73785b9f5..bf9f7ad573 100644
--- a/protocols/JabberG/src/jabber_iq_handlers.cpp
+++ b/protocols/JabberG/src/jabber_iq_handlers.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_iqid.cpp b/protocols/JabberG/src/jabber_iqid.cpp
index df222552fa..68783083c7 100644
--- a/protocols/JabberG/src/jabber_iqid.cpp
+++ b/protocols/JabberG/src/jabber_iqid.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_iqid_muc.cpp b/protocols/JabberG/src/jabber_iqid_muc.cpp
index 8bf9621ab6..f811d7cb82 100644
--- a/protocols/JabberG/src/jabber_iqid_muc.cpp
+++ b/protocols/JabberG/src/jabber_iqid_muc.cpp
@@ -4,7 +4,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_libstr.cpp b/protocols/JabberG/src/jabber_libstr.cpp
index 0c20ff4cc2..2b7e91aea5 100644
--- a/protocols/JabberG/src/jabber_libstr.cpp
+++ b/protocols/JabberG/src/jabber_libstr.cpp
@@ -4,7 +4,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_list.cpp b/protocols/JabberG/src/jabber_list.cpp
index bbfbb1d35e..73abe09e2b 100644
--- a/protocols/JabberG/src/jabber_list.cpp
+++ b/protocols/JabberG/src/jabber_list.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_list.h b/protocols/JabberG/src/jabber_list.h
index 082d247350..e418131443 100644
--- a/protocols/JabberG/src/jabber_list.h
+++ b/protocols/JabberG/src/jabber_list.h
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_mam.cpp b/protocols/JabberG/src/jabber_mam.cpp
index 989630ac07..0665e5df2f 100644
--- a/protocols/JabberG/src/jabber_mam.cpp
+++ b/protocols/JabberG/src/jabber_mam.cpp
@@ -1,160 +1,160 @@
-/*
-
-Jabber Protocol Plugin for Miranda NG
-
-Copyright (c) 2002-04 Santithorn Bunchua
-Copyright (c) 2005-12 George Hazan
-Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
-
-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; either version 2
-of the License, or (at your option) any later version.
-
-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, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-
-#include "stdafx.h"
-#include "jabber_iq.h"
-#include "jabber_caps.h"
-
-void CJabberProto::OnIqResultMamInfo(const TiXmlElement *iqNode, CJabberIqInfo *pInfo)
-{
- if (pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT) {
- if (auto *n = XmlFirstChild(iqNode, "prefs")) {
- m_bMamPrefsAvailable = true;
-
- if (auto *type = n->Attribute("default")) {
- if (!strcmp(type, "never"))
- m_iMamMode = 0;
- else if (!strcmp(type, "roster"))
- m_iMamMode = 1;
- else
- m_iMamMode = 2;
- }
- }
- }
-
- // shall we retrieve missing messages?
- if (pInfo->GetUserData())
- MamRetrieveMissingMessages();
-}
-
-void CJabberProto::MamSetMode(int iNewMode)
-{
- if (!m_bEnableMam)
- return;
-
- const char *szMode;
- switch (iNewMode) {
- case 0: szMode = "never"; break;
- case 1: szMode = "roster"; break;
- default: szMode = "always"; break;
- }
-
- XmlNodeIq iq(AddIQ(&CJabberProto::OnIqResultMamInfo, JABBER_IQ_TYPE_SET));
- auto *node = iq << XCHILDNS("prefs", JABBER_FEAT_MAM) << XATTR("default", szMode);
- node << XCHILD("always"); node << XCHILD("never");
- m_ThreadInfo->send(iq);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
-void CJabberProto::MamRetrieveMissingMessages()
-{
- CMStringA szLastId = getMStringA("LastMamId");
-
- XmlNodeIq iq("set", SerialNext());
- auto *query = iq << XCHILDNS("query", JABBER_FEAT_MAM);
-
- if (szLastId.IsEmpty()) {
- m_bMamDisableMessages = true; // our goal is to save message id, not to store messages
- m_bMamCreateRead = false;
-
- char buf[100];
- time2str(time(0), buf, _countof(buf));
-
- auto *form = query << XCHILDNS("x", JABBER_FEAT_DATA_FORMS) << XATTR("type", "submit");
- form << XCHILD("field") << XATTR("var", "FORM_TYPE") << XATTR("type", "hidden") << XCHILD("value", JABBER_FEAT_MAM);
- form << XCHILD("field") << XATTR("var", "end") << XCHILD("value", buf);
- }
- else {
- auto *set = query << XCHILDNS("set", "http://jabber.org/protocol/rsm");
- set << XCHILD("max", "1000");
- set << XCHILD("after", szLastId);
- }
-
- m_ThreadInfo->send(iq);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Contact's history loader
-
-void CJabberProto::MamSendForm(const char *pszWith, const char *pszAfter)
-{
- auto *pReq = AddIQ(&CJabberProto::OnIqResultRsm, JABBER_IQ_TYPE_SET);
- pReq->SetParamsToParse(JABBER_IQ_PARSE_FROM);
-
- XmlNodeIq iq(pReq);
- auto *query = iq << XCHILDNS("query", JABBER_FEAT_MAM);
-
- auto *form = query << XCHILDNS("x", JABBER_FEAT_DATA_FORMS) << XATTR("type", "submit");
- form << XCHILD("field") << XATTR("var", "FORM_TYPE") << XATTR("type", "hidden") << XCHILD("value", JABBER_FEAT_MAM);
- if (pszWith != nullptr)
- form << XCHILD("field") << XATTR("var", "with") << XCHILD("value", pszWith);
-
- auto *rsm = query << XCHILDNS("set", "http://jabber.org/protocol/rsm");
- rsm << XCHILD("max", "1000");
- if (pszAfter != nullptr)
- rsm << XCHILD("after", pszAfter);
- m_ThreadInfo->send(iq);
-}
-
-
-void CJabberProto::OnIqResultRsm(const TiXmlElement *iqNode, CJabberIqInfo *pInfo)
-{
- // even if that flag was enabled, unset it
- m_bMamDisableMessages = false;
-
- if (auto *fin = XmlGetChildByTag(iqNode, "fin", "xmlns", JABBER_FEAT_MAM)) {
- // if dataset is complete, there's nothing more to do
- if (!mir_strcmp(XmlGetAttr(fin, "complete"), "true"))
- return;
-
- if (auto *set = XmlGetChildByTag(fin, "set", "xmlns", "http://jabber.org/protocol/rsm"))
- if (auto *lastId = XmlGetChildText(set, "last"))
- MamSendForm(ptrA(getUStringA(pInfo->GetHContact(), "jid")), lastId);
- }
-}
-
-INT_PTR __cdecl CJabberProto::OnMenuLoadHistory(WPARAM hContact, LPARAM)
-{
- if (hContact == 0 || !m_bEnableMam)
- return 0;
-
- // wipe out old history first
- if (IDYES == MessageBoxW(NULL, TranslateT("Do you want to erase local history before loading it from server?"), m_tszUserName, MB_YESNOCANCEL | MB_ICONQUESTION)) {
- DB::ECPTR pCursor(DB::Events(hContact));
- while (pCursor.FetchNext())
- pCursor.DeleteEvent();
- }
-
- // load remaining items from server
- if (m_bJabberOnline) {
- ptrA jid(getUStringA(hContact, "jid"));
- if (jid != nullptr) {
- m_bMamCreateRead = true;
- MamSendForm(jid);
- }
- }
- return 0;
-}
+/*
+
+Jabber Protocol Plugin for Miranda NG
+
+Copyright (c) 2002-04 Santithorn Bunchua
+Copyright (c) 2005-12 George Hazan
+Copyright (c) 2007 Maxim Mluhov
+Copyright (C) 2012-23 Miranda NG team
+
+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; either version 2
+of the License, or (at your option) any later version.
+
+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, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "stdafx.h"
+#include "jabber_iq.h"
+#include "jabber_caps.h"
+
+void CJabberProto::OnIqResultMamInfo(const TiXmlElement *iqNode, CJabberIqInfo *pInfo)
+{
+ if (pInfo->GetIqType() == JABBER_IQ_TYPE_RESULT) {
+ if (auto *n = XmlFirstChild(iqNode, "prefs")) {
+ m_bMamPrefsAvailable = true;
+
+ if (auto *type = n->Attribute("default")) {
+ if (!strcmp(type, "never"))
+ m_iMamMode = 0;
+ else if (!strcmp(type, "roster"))
+ m_iMamMode = 1;
+ else
+ m_iMamMode = 2;
+ }
+ }
+ }
+
+ // shall we retrieve missing messages?
+ if (pInfo->GetUserData())
+ MamRetrieveMissingMessages();
+}
+
+void CJabberProto::MamSetMode(int iNewMode)
+{
+ if (!m_bEnableMam)
+ return;
+
+ const char *szMode;
+ switch (iNewMode) {
+ case 0: szMode = "never"; break;
+ case 1: szMode = "roster"; break;
+ default: szMode = "always"; break;
+ }
+
+ XmlNodeIq iq(AddIQ(&CJabberProto::OnIqResultMamInfo, JABBER_IQ_TYPE_SET));
+ auto *node = iq << XCHILDNS("prefs", JABBER_FEAT_MAM) << XATTR("default", szMode);
+ node << XCHILD("always"); node << XCHILD("never");
+ m_ThreadInfo->send(iq);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CJabberProto::MamRetrieveMissingMessages()
+{
+ CMStringA szLastId = getMStringA("LastMamId");
+
+ XmlNodeIq iq("set", SerialNext());
+ auto *query = iq << XCHILDNS("query", JABBER_FEAT_MAM);
+
+ if (szLastId.IsEmpty()) {
+ m_bMamDisableMessages = true; // our goal is to save message id, not to store messages
+ m_bMamCreateRead = false;
+
+ char buf[100];
+ time2str(time(0), buf, _countof(buf));
+
+ auto *form = query << XCHILDNS("x", JABBER_FEAT_DATA_FORMS) << XATTR("type", "submit");
+ form << XCHILD("field") << XATTR("var", "FORM_TYPE") << XATTR("type", "hidden") << XCHILD("value", JABBER_FEAT_MAM);
+ form << XCHILD("field") << XATTR("var", "end") << XCHILD("value", buf);
+ }
+ else {
+ auto *set = query << XCHILDNS("set", "http://jabber.org/protocol/rsm");
+ set << XCHILD("max", "1000");
+ set << XCHILD("after", szLastId);
+ }
+
+ m_ThreadInfo->send(iq);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Contact's history loader
+
+void CJabberProto::MamSendForm(const char *pszWith, const char *pszAfter)
+{
+ auto *pReq = AddIQ(&CJabberProto::OnIqResultRsm, JABBER_IQ_TYPE_SET);
+ pReq->SetParamsToParse(JABBER_IQ_PARSE_FROM);
+
+ XmlNodeIq iq(pReq);
+ auto *query = iq << XCHILDNS("query", JABBER_FEAT_MAM);
+
+ auto *form = query << XCHILDNS("x", JABBER_FEAT_DATA_FORMS) << XATTR("type", "submit");
+ form << XCHILD("field") << XATTR("var", "FORM_TYPE") << XATTR("type", "hidden") << XCHILD("value", JABBER_FEAT_MAM);
+ if (pszWith != nullptr)
+ form << XCHILD("field") << XATTR("var", "with") << XCHILD("value", pszWith);
+
+ auto *rsm = query << XCHILDNS("set", "http://jabber.org/protocol/rsm");
+ rsm << XCHILD("max", "1000");
+ if (pszAfter != nullptr)
+ rsm << XCHILD("after", pszAfter);
+ m_ThreadInfo->send(iq);
+}
+
+
+void CJabberProto::OnIqResultRsm(const TiXmlElement *iqNode, CJabberIqInfo *pInfo)
+{
+ // even if that flag was enabled, unset it
+ m_bMamDisableMessages = false;
+
+ if (auto *fin = XmlGetChildByTag(iqNode, "fin", "xmlns", JABBER_FEAT_MAM)) {
+ // if dataset is complete, there's nothing more to do
+ if (!mir_strcmp(XmlGetAttr(fin, "complete"), "true"))
+ return;
+
+ if (auto *set = XmlGetChildByTag(fin, "set", "xmlns", "http://jabber.org/protocol/rsm"))
+ if (auto *lastId = XmlGetChildText(set, "last"))
+ MamSendForm(ptrA(getUStringA(pInfo->GetHContact(), "jid")), lastId);
+ }
+}
+
+INT_PTR __cdecl CJabberProto::OnMenuLoadHistory(WPARAM hContact, LPARAM)
+{
+ if (hContact == 0 || !m_bEnableMam)
+ return 0;
+
+ // wipe out old history first
+ if (IDYES == MessageBoxW(NULL, TranslateT("Do you want to erase local history before loading it from server?"), m_tszUserName, MB_YESNOCANCEL | MB_ICONQUESTION)) {
+ DB::ECPTR pCursor(DB::Events(hContact));
+ while (pCursor.FetchNext())
+ pCursor.DeleteEvent();
+ }
+
+ // load remaining items from server
+ if (m_bJabberOnline) {
+ ptrA jid(getUStringA(hContact, "jid"));
+ if (jid != nullptr) {
+ m_bMamCreateRead = true;
+ MamSendForm(jid);
+ }
+ }
+ return 0;
+}
diff --git a/protocols/JabberG/src/jabber_menu.cpp b/protocols/JabberG/src/jabber_menu.cpp
index 920d390f1a..0d510f6859 100644
--- a/protocols/JabberG/src/jabber_menu.cpp
+++ b/protocols/JabberG/src/jabber_menu.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_message_handlers.cpp b/protocols/JabberG/src/jabber_message_handlers.cpp
index 4301a4a5c8..7610908dfe 100644
--- a/protocols/JabberG/src/jabber_message_handlers.cpp
+++ b/protocols/JabberG/src/jabber_message_handlers.cpp
@@ -6,7 +6,7 @@ Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-08 George Hazan
Copyright (c) 2007 Maxim Mluhov
Copyright (c) 2008-09 Dmitriy Chervov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_message_manager.cpp b/protocols/JabberG/src/jabber_message_manager.cpp
index a794974a41..b1db1f299a 100644
--- a/protocols/JabberG/src/jabber_message_manager.cpp
+++ b/protocols/JabberG/src/jabber_message_manager.cpp
@@ -6,7 +6,7 @@ Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-08 George Hazan
Copyright (c) 2007 Maxim Mluhov
Copyright (c) 2008-09 Dmitriy Chervov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_message_manager.h b/protocols/JabberG/src/jabber_message_manager.h
index 07d381e90f..f7ae0d82ee 100644
--- a/protocols/JabberG/src/jabber_message_manager.h
+++ b/protocols/JabberG/src/jabber_message_manager.h
@@ -6,7 +6,7 @@ Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-08 George Hazan
Copyright (c) 2007 Maxim Mluhov
Copyright (c) 2008-09 Dmitriy Chervov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_misc.cpp b/protocols/JabberG/src/jabber_misc.cpp
index 88a6909eca..71115ef87a 100644
--- a/protocols/JabberG/src/jabber_misc.cpp
+++ b/protocols/JabberG/src/jabber_misc.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_notes.cpp b/protocols/JabberG/src/jabber_notes.cpp
index 6734e7c26c..ac6272f5b7 100644
--- a/protocols/JabberG/src/jabber_notes.cpp
+++ b/protocols/JabberG/src/jabber_notes.cpp
@@ -6,7 +6,7 @@ Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007-09 Maxim Mluhov
Copyright (c) 2007-09 Victor Pavlychko
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_notes.h b/protocols/JabberG/src/jabber_notes.h
index d103a938f4..bb7cc22181 100644
--- a/protocols/JabberG/src/jabber_notes.h
+++ b/protocols/JabberG/src/jabber_notes.h
@@ -6,7 +6,7 @@ Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007-09 Maxim Mluhov
Copyright (c) 2007-09 Victor Pavlychko
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_omemo.cpp b/protocols/JabberG/src/jabber_omemo.cpp
index e5edb53d57..f51245d6bd 100644
--- a/protocols/JabberG/src/jabber_omemo.cpp
+++ b/protocols/JabberG/src/jabber_omemo.cpp
@@ -2,7 +2,7 @@
Jabber Protocol Plugin for Miranda NG
-Copyright (c) 2017-22 Miranda NG team
+Copyright (c) 2017-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_omemo.h b/protocols/JabberG/src/jabber_omemo.h
index 8563735c36..94b9fd8dbb 100644
--- a/protocols/JabberG/src/jabber_omemo.h
+++ b/protocols/JabberG/src/jabber_omemo.h
@@ -2,7 +2,7 @@
Jabber Protocol Plugin for Miranda NG
-Copyright (c) 2017-22 Miranda NG team
+Copyright (c) 2017-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_opt.cpp b/protocols/JabberG/src/jabber_opt.cpp
index c3f735c223..c7e85211cd 100644
--- a/protocols/JabberG/src/jabber_opt.cpp
+++ b/protocols/JabberG/src/jabber_opt.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_password.cpp b/protocols/JabberG/src/jabber_password.cpp
index d39c6a5aa5..0fe0700998 100644
--- a/protocols/JabberG/src/jabber_password.cpp
+++ b/protocols/JabberG/src/jabber_password.cpp
@@ -4,7 +4,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_presence_manager.cpp b/protocols/JabberG/src/jabber_presence_manager.cpp
index de0dabbe65..873b2a1076 100644
--- a/protocols/JabberG/src/jabber_presence_manager.cpp
+++ b/protocols/JabberG/src/jabber_presence_manager.cpp
@@ -6,7 +6,7 @@ Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-08 George Hazan
Copyright (c) 2007 Maxim Mluhov
Copyright (c) 2008-09 Dmitriy Chervov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_presence_manager.h b/protocols/JabberG/src/jabber_presence_manager.h
index 4dab8a4991..0c488747c5 100644
--- a/protocols/JabberG/src/jabber_presence_manager.h
+++ b/protocols/JabberG/src/jabber_presence_manager.h
@@ -6,7 +6,7 @@ Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-08 George Hazan
Copyright (c) 2007 Maxim Mluhov
Copyright (c) 2008-09 Dmitriy Chervov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_privacy.cpp b/protocols/JabberG/src/jabber_privacy.cpp
index 8a02af9bba..b1087fde09 100644
--- a/protocols/JabberG/src/jabber_privacy.cpp
+++ b/protocols/JabberG/src/jabber_privacy.cpp
@@ -6,7 +6,7 @@ Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007-09 Maxim Mluhov
Copyright (c) 2007-09 Victor Pavlychko
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_privacy.h b/protocols/JabberG/src/jabber_privacy.h
index 4ad6f4294a..d6918a5f1e 100644
--- a/protocols/JabberG/src/jabber_privacy.h
+++ b/protocols/JabberG/src/jabber_privacy.h
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_proto.cpp b/protocols/JabberG/src/jabber_proto.cpp
index 8e2f349cb6..3811becab3 100644
--- a/protocols/JabberG/src/jabber_proto.cpp
+++ b/protocols/JabberG/src/jabber_proto.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h
index 29b05e25c0..6037019f46 100644
--- a/protocols/JabberG/src/jabber_proto.h
+++ b/protocols/JabberG/src/jabber_proto.h
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_rc.cpp b/protocols/JabberG/src/jabber_rc.cpp
index 99e642d38d..a5bae9e944 100644
--- a/protocols/JabberG/src/jabber_rc.cpp
+++ b/protocols/JabberG/src/jabber_rc.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
XEP-0146 support for Miranda IM
diff --git a/protocols/JabberG/src/jabber_rc.h b/protocols/JabberG/src/jabber_rc.h
index 430261602d..7549723872 100644
--- a/protocols/JabberG/src/jabber_rc.h
+++ b/protocols/JabberG/src/jabber_rc.h
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
XEP-0146 support for Miranda IM
diff --git a/protocols/JabberG/src/jabber_roster.cpp b/protocols/JabberG/src/jabber_roster.cpp
index 5072fe9ebb..03d9e9ffdd 100644
--- a/protocols/JabberG/src/jabber_roster.cpp
+++ b/protocols/JabberG/src/jabber_roster.cpp
@@ -1,551 +1,551 @@
-/*
-
-Jabber Protocol Plugin for Miranda NG
-
-Copyright (c) 2002-04 Santithorn Bunchua
-Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
-
-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; either version 2
-of the License, or (at your option) any later version.
-
-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, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-
-#include "stdafx.h"
-
-#include <io.h>
-
-//////////////////////////////////////////////////////////////////////////
-// roster editor
-//
-
-enum
-{
- RRA_FILLLIST = 0,
- RRA_SYNCROSTER,
- RRA_SYNCDONE
-};
-
-struct ROSTEREDITDAT
-{
- HWND hList;
- int index;
- int subindex;
-};
-
-static void _RosterItemEditEnd(HWND hEditor, ROSTEREDITDAT *edat, BOOL bCancel)
-{
- if (!bCancel) {
- int len = GetWindowTextLength(hEditor) + 1;
- wchar_t *buff = (wchar_t*)mir_alloc(len*sizeof(wchar_t));
- if (buff) {
- GetWindowText(hEditor, buff, len);
- ListView_SetItemText(edat->hList, edat->index, edat->subindex, buff);
- }
- mir_free(buff);
- }
- DestroyWindow(hEditor);
-}
-
-static LRESULT CALLBACK _RosterItemNewEditProc(HWND hEditor, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- ROSTEREDITDAT * edat = (ROSTEREDITDAT *)GetWindowLongPtr(hEditor, GWLP_USERDATA);
- if (!edat) return 0;
- switch (msg) {
- case WM_KEYDOWN:
- switch (wParam) {
- case VK_RETURN:
- _RosterItemEditEnd(hEditor, edat, FALSE);
- return 0;
- case VK_ESCAPE:
- _RosterItemEditEnd(hEditor, edat, TRUE);
- return 0;
- }
- break;
-
- case WM_GETDLGCODE:
- if (lParam) {
- MSG *msg2 = (MSG*)lParam;
- if (msg2->message == WM_KEYDOWN && msg2->wParam == VK_TAB) return 0;
- if (msg2->message == WM_CHAR && msg2->wParam == '\t') return 0;
- }
- return DLGC_WANTMESSAGE;
-
- case WM_KILLFOCUS:
- _RosterItemEditEnd(hEditor, edat, FALSE);
- return 0;
-
- case WM_DESTROY:
- SetWindowLongPtr(hEditor, GWLP_USERDATA, (LONG_PTR)0);
- free(edat);
- return 0;
- }
-
- return mir_callNextSubclass(hEditor, _RosterItemNewEditProc, msg, wParam, lParam);
-}
-
-static LRESULT CALLBACK _RosterNewListProc(HWND hList, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- if (msg == WM_MOUSEWHEEL || msg == WM_NCLBUTTONDOWN || msg == WM_NCRBUTTONDOWN)
- SetFocus(hList);
-
- if (msg == WM_LBUTTONDOWN) {
- POINT pt;
- GetCursorPos(&pt);
- ScreenToClient(hList, &pt);
-
- LVHITTESTINFO lvhti = { 0 };
- lvhti.pt = pt;
- ListView_SubItemHitTest(hList, &lvhti);
- if (lvhti.flags&LVHT_ONITEM && lvhti.iSubItem != 0) {
- RECT rc;
- wchar_t buff[260];
- ListView_GetSubItemRect(hList, lvhti.iItem, lvhti.iSubItem, LVIR_BOUNDS, &rc);
- ListView_GetItemText(hList, lvhti.iItem, lvhti.iSubItem, buff, _countof(buff));
- HWND hEditor = CreateWindow(TEXT("EDIT"), buff, WS_CHILD | ES_AUTOHSCROLL, rc.left + 3, rc.top + 2, rc.right - rc.left - 3, rc.bottom - rc.top - 3, hList, nullptr, g_plugin.getInst(), nullptr);
- SendMessage(hEditor, WM_SETFONT, (WPARAM)SendMessage(hList, WM_GETFONT, 0, 0), 0);
- ShowWindow(hEditor, SW_SHOW);
- SetWindowText(hEditor, buff);
- ClientToScreen(hList, &pt);
- ScreenToClient(hEditor, &pt);
- mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
- mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
-
- ROSTEREDITDAT * edat = (ROSTEREDITDAT *)malloc(sizeof(ROSTEREDITDAT));
- mir_subclassWindow(hEditor, _RosterItemNewEditProc);
- edat->hList = hList;
- edat->index = lvhti.iItem;
- edat->subindex = lvhti.iSubItem;
- SetWindowLongPtr(hEditor, GWLP_USERDATA, (LONG_PTR)edat);
- }
- }
- return mir_callNextSubclass(hList, _RosterNewListProc, msg, wParam, lParam);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// JabberRosterOptDlgProc - advanced options dialog procedure
-
-class CRosterEditorDlg : public CJabberDlgBase
-{
- friend struct CJabberProto;
- typedef CJabberDlgBase CSuper;
-
- uint8_t m_bRRAction;
- BOOL m_bReadyToDownload = true;
- BOOL m_bReadyToUpload = false;
-
- void _RosterSendRequest(uint8_t rrAction)
- {
- m_bRRAction = rrAction;
-
- m_proto->m_ThreadInfo->send(
- XmlNodeIq(m_proto->AddIQ(&CJabberProto::_RosterHandleGetRequest, JABBER_IQ_TYPE_GET))
- << XCHILDNS("query", JABBER_FEAT_IQ_ROSTER));
- }
-
- int _RosterInsertListItem(const char *jid, const char *nick, const char *group, const char *subscr, bool bChecked)
- {
- Utf2T wszJid(jid);
- LVITEM item = { 0 };
- item.mask = LVIF_TEXT | LVIF_STATE;
- item.iItem = m_list.GetItemCount();
- item.pszText = wszJid;
-
- int index = m_list.InsertItem(&item);
- if (index < 0)
- return index;
-
- m_list.SetCheckState(index, bChecked);
-
- m_list.SetItemText(index, 1, Utf2T(nick));
- m_list.SetItemText(index, 2, Utf2T(group));
- m_list.SetItemText(index, 3, TranslateW(Utf2T(subscr)));
- return index;
- }
-
- void _RosterListClear()
- {
- m_list.DeleteAllItems();
- while (m_list.GetColumnWidth(0) > 0)
- m_list.DeleteColumn(0);
-
- LV_COLUMN column = { 0 };
- column.mask = LVCF_TEXT;
-
- column.pszText = TranslateT("JID");
- m_list.InsertColumn(1, &column);
-
- column.pszText = TranslateT("Nickname");
- m_list.InsertColumn(2, &column);
-
- column.pszText = TranslateT("Group");
- m_list.InsertColumn(3, &column);
-
- column.pszText = TranslateT("Subscription");
- m_list.InsertColumn(4, &column);
-
- RECT rc;
- GetClientRect(m_list.GetHwnd(), &rc);
- ResizeColumns(rc.right - rc.left);
- }
-
- void ResizeColumns(int width)
- {
- m_list.SetColumnWidth(0, width * 40 / 100);
- m_list.SetColumnWidth(1, width * 25 / 100);
- m_list.SetColumnWidth(2, width * 20 / 100);
- m_list.SetColumnWidth(3, width * 12 / 100);
- }
-
- void OnChangeStatus()
- {
- int count = m_list.GetItemCount();
- btnDownload.Enable(m_proto->m_bJabberOnline);
- btnUpload.Enable(count && m_proto->m_bJabberOnline);
- btnExport.Enable(count > 0);
- }
-
- CCtrlButton btnDownload, btnUpload, btnExport, btnImport;
- CCtrlListView m_list;
-
-public:
- CRosterEditorDlg(CJabberProto *m_proto) :
- CSuper(m_proto, IDD_ROSTER_EDITOR),
- m_list(this, IDC_ROSTER),
- btnExport(this, IDC_EXPORT),
- btnImport(this, IDC_IMPORT),
- btnUpload(this, IDC_UPLOAD),
- btnDownload(this, IDC_DOWNLOAD)
- {
- SetMinSize(550, 390);
-
- btnExport.OnClick = Callback(this, &CRosterEditorDlg::onClick_Export);
- btnImport.OnClick = Callback(this, &CRosterEditorDlg::onClick_Import);
- btnUpload.OnClick = Callback(this, &CRosterEditorDlg::onClick_Upload);
- btnDownload.OnClick = Callback(this, &CRosterEditorDlg::onClick_Download);
- }
-
- bool OnInitDialog() override
- {
- SetWindowTextW(m_hwnd, CMStringW(FORMAT, L"%s: %s", TranslateT("Roster Editor"), m_proto->m_tszUserName));
-
- Window_SetIcon_IcoLib(m_hwnd, g_plugin.getIconHandle(IDI_AGENTS));
-
- Utils_RestoreWindowPosition(m_hwnd, 0, m_proto->m_szModuleName, "rosterCtrlWnd_");
-
- m_list.SetExtendedListViewStyle(LVS_EX_CHECKBOXES | LVS_EX_BORDERSELECT | LVS_EX_GRIDLINES);
- mir_subclassWindow(m_list.GetHwnd(), _RosterNewListProc);
- _RosterListClear();
- OnChangeStatus();
- return true;
- }
-
- void OnDestroy() override
- {
- m_proto->m_hwndRosterEditor = nullptr;
- Utils_SaveWindowPosition(m_hwnd, 0, m_proto->m_szModuleName, "rosterCtrlWnd_");
- Window_FreeIcon_IcoLib(m_hwnd);
- }
-
- int Resizer(UTILRESIZECONTROL *urc) override
- {
- switch (urc->wId) {
- case IDC_HEADERBAR:
- return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORX_WIDTH;
- case IDC_ROSTER:
- ResizeColumns(urc->rcItem.right - urc->rcItem.left + urc->dlgNewSize.cx - urc->dlgOriginalSize.cx);
- return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORY_HEIGHT | RD_ANCHORX_WIDTH;
- case IDC_DOWNLOAD:
- case IDC_UPLOAD:
- return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM;
- case IDC_EXPORT:
- case IDC_IMPORT:
- return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM;
- }
- return RD_ANCHORX_LEFT | RD_ANCHORY_TOP;
- }
-
- void HandleNode(const TiXmlElement *node)
- {
- if (m_bRRAction == RRA_FILLLIST) {
- _RosterListClear();
- auto *query = XmlFirstChild(node, "query");
- if (query == nullptr) return;
-
- for (auto *item : TiXmlFilter(query, "item")) {
- const char *jid = XmlGetAttr(item, "jid");
- if (jid == nullptr)
- continue;
-
- const char *name = XmlGetAttr(item, "name");
- const char *subscription = XmlGetAttr(item, "subscription");
- const char *group = XmlGetChildText(item, "group");
- _RosterInsertListItem(jid, name, group, subscription, true);
- }
-
- // now it is require to process whole contact list to add not in roster contacts
- for (auto &hContact : m_proto->AccContacts()) {
- ptrW tszJid(m_proto->getWStringA(hContact, "jid"));
- if (tszJid == nullptr)
- continue;
-
- LVFINDINFO lvfi = { 0 };
- lvfi.flags = LVFI_STRING;
- lvfi.psz = tszJid;
- if (m_list.FindItem(-1, &lvfi) == -1) {
- ptrA tszName(db_get_utfa(hContact, "CList", "MyHandle"));
- ptrA tszGroup(db_get_utfa(hContact, "CList", "Group"));
- _RosterInsertListItem(T2Utf(tszJid), tszName, tszGroup, nullptr, false);
- }
- }
- m_bReadyToDownload = false;
- m_bReadyToUpload = true;
- btnDownload.SetText(TranslateT("Download"));
- btnUpload.SetText(TranslateT("Upload"));
- OnChangeStatus();
- return;
- }
-
- if (m_bRRAction == RRA_SYNCROSTER) {
- btnUpload.SetText(TranslateT("Uploading..."));
- auto *queryRoster = XmlFirstChild(node, "query");
- if (!queryRoster)
- return;
-
- int ListItemCount = m_list.GetItemCount();
- for (int index = 0; index < ListItemCount; index++) {
- wchar_t jid[JABBER_MAX_JID_LEN] = L"";
- wchar_t name[260];
- wchar_t group[260];
- wchar_t subscr[260];
- m_list.GetItemText(index, 0, jid, _countof(jid));
- m_list.GetItemText(index, 1, name, _countof(name));
- m_list.GetItemText(index, 2, group, _countof(group));
- m_list.GetItemText(index, 3, subscr, _countof(subscr));
-
- T2Utf szJid(jid), szName(name), szGroup(group), szSubscr(subscr);
- auto *itemRoster = XmlGetChildByTag(queryRoster, "item", "jid", szJid);
- bool bRemove = !m_list.GetCheckState(index);
- if (itemRoster && bRemove) { // delete item
- XmlNodeIq iq(m_proto->AddIQ(&CJabberProto::_RosterHandleGetRequest, JABBER_IQ_TYPE_SET));
- iq << XCHILDNS("query", JABBER_FEAT_IQ_ROSTER) << XCHILD("item") << XATTR("jid", szJid) << XATTR("subscription", "remove");
- m_proto->m_ThreadInfo->send(iq);
- }
- else if (!bRemove) {
- bool bPushed = itemRoster != 0;
- const char *rosterName = 0, *rosterGroup = 0;
- if (!bPushed) {
- rosterName = XmlGetAttr(itemRoster, "name");
- if ((rosterName != nullptr || name[0] != 0) && mir_strcmpi(rosterName, szName))
- bPushed = true;
- if (!bPushed) {
- auto *szSub = XmlGetAttr(itemRoster, "subscription");
- if ((szSub != nullptr || subscr[0] != 0) && mir_strcmpi(szSub, szSubscr))
- bPushed = true;
- }
- if (!bPushed) {
- rosterGroup = XmlGetChildText(itemRoster, "group");
- if (rosterGroup != nullptr && mir_strcmpi(rosterGroup, szGroup))
- bPushed = true;
- }
- }
- if (bPushed) {
- XmlNodeIq iq(m_proto->AddIQ(&CJabberProto::_RosterHandleGetRequest, JABBER_IQ_TYPE_SET));
- auto *item = iq << XCHILDNS("query", JABBER_FEAT_IQ_ROSTER) << XCHILD("item");
- if (rosterGroup || mir_strlen(szGroup))
- item << XCHILD("group", szGroup);
- if (rosterName || mir_strlen(szName))
- item << XATTR("name", szName);
- item << XATTR("jid", szJid) << XATTR("subscription", subscr[0] ? szSubscr : "none");
- m_proto->m_ThreadInfo->send(iq);
- }
- }
- }
- m_bRRAction = RRA_SYNCDONE;
- _RosterSendRequest(RRA_FILLLIST);
- return;
- }
-
- btnUpload.SetText(TranslateT("Upload"));
- onClick_Download(nullptr);
- };
-
- void onClick_Download(CCtrlButton*)
- {
- m_bReadyToUpload = m_bReadyToDownload = false;
- OnChangeStatus();
- btnDownload.SetText(TranslateT("Downloading..."));
- _RosterSendRequest(RRA_FILLLIST);
- }
-
- void onClick_Upload(CCtrlButton*)
- {
- m_bReadyToUpload = false;
- OnChangeStatus();
- btnUpload.SetText(TranslateT("Connecting..."));
- _RosterSendRequest(RRA_SYNCROSTER);
- }
-
- void onClick_Export(CCtrlButton*)
- {
- wchar_t filename[MAX_PATH] = { 0 };
-
- wchar_t filter[MAX_PATH];
- mir_snwprintf(filter, L"%s (*.xml)%c*.xml%c%c", TranslateT("XML (UTF-8 encoded)"), 0, 0, 0);
- OPENFILENAME ofn = {};
- ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
- ofn.hwndOwner = m_hwnd;
- ofn.lpstrFilter = filter;
- ofn.lpstrFile = filename;
- ofn.Flags = OFN_HIDEREADONLY;
- ofn.nMaxFile = _countof(filename);
- ofn.nMaxFileTitle = MAX_PATH;
- ofn.lpstrDefExt = L"xml";
- if (!GetSaveFileNameW(&ofn))
- return;
-
- FILE * fp = _wfopen(filename, L"wb");
- if (!fp)
- return;
-
- int ListItemCount = m_list.GetItemCount();
-
- XmlNode root("Roster");
-
- for (int index = 0; index < ListItemCount; index++) {
- wchar_t jid[JABBER_MAX_JID_LEN] = L"";
- wchar_t name[260] = L"";
- wchar_t group[260] = L"";
- wchar_t subscr[260] = L"";
- m_list.GetItemText(index, 0, jid, _countof(jid));
- m_list.GetItemText(index, 1, name, _countof(name));
- m_list.GetItemText(index, 2, group, _countof(group));
- m_list.GetItemText(index, 3, subscr, _countof(subscr));
- root << XCHILD("Item") << XATTR("jid", T2Utf(jid)) << XATTR("name", T2Utf(name)) << XATTR("group", T2Utf(group)) << XATTR("subscription", T2Utf(subscr));
- }
-
- tinyxml2::XMLPrinter printer(fp);
- root.Print(&printer);
- fclose(fp);
- }
-
- void onClick_Import(CCtrlButton*)
- {
- wchar_t filename[MAX_PATH] = {};
-
- OPENFILENAME ofn = { 0 };
- ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
- ofn.hwndOwner = m_hwnd;
- ofn.hInstance = nullptr;
- ofn.lpstrFilter = L"XML (UTF-8 encoded)(*.xml)\0*.xml\0\0";
- ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
- ofn.lpstrFile = filename;
- ofn.nMaxFile = _countof(filename);
- ofn.nMaxFileTitle = MAX_PATH;
- ofn.lpstrDefExt = L"xml";
- if (!GetOpenFileNameW(&ofn))
- return;
-
- FILE * fp = _wfopen(filename, L"rb");
- if (!fp)
- return;
-
- TiXmlDocument doc;
- int ret = doc.LoadFile(fp);
- fclose(fp);
- if (ret != 0)
- return;
-
- _RosterListClear();
-
- const TiXmlElement *Table = TiXmlConst(&doc)["Workbook"]["Worksheet"]["Table"].ToElement();
- if (Table) {
- for (auto *Row : TiXmlFilter(Table, "Row")) {
- bool bAdd = false;
- const char *jid = nullptr;
- const char *name = nullptr;
- const char *group = nullptr;
- const char *subscr = nullptr;
- auto *Cell = XmlFirstChild(Row, "Cell");
- auto *Data = XmlFirstChild(Cell, "Data");
- if (Data) {
- if (!mir_strcmpi(Data->GetText(), "+"))
- bAdd = true;
- else if (mir_strcmpi(Data->GetText(), "-"))
- continue;
-
- Cell = Cell->NextSiblingElement("Cell");
- if (Cell) Data = XmlFirstChild(Cell, "Data");
- else Data = nullptr;
- if (Data) {
- jid = Data->GetText();
- if (!jid || mir_strlen(jid) == 0)
- continue;
- }
-
- Cell = Cell->NextSiblingElement("Cell");
- if (Cell) Data = XmlFirstChild(Cell, "Data");
- else Data = nullptr;
- if (Data) name = Data->GetText();
-
- Cell = Cell->NextSiblingElement("Cell");
- if (Cell) Data = XmlFirstChild(Cell, "Data");
- else Data = nullptr;
- if (Data) group = Data->GetText();
-
- Cell = Cell->NextSiblingElement("Cell");
- if (Cell) Data = XmlFirstChild(Cell, "Data");
- else Data = nullptr;
- if (Data) subscr = Data->GetText();
- }
- _RosterInsertListItem(jid, name, group, subscr, bAdd);
- }
- }
- else if (Table = TiXmlConst(&doc)["Roster"].ToElement()) {
- for (auto *Row : TiXmlFilter(Table, "Item")) {
- auto *jid = Row->Attribute("jid");
- auto *name = Row->Attribute("name");
- auto *group = Row->Attribute("group");
- auto *subscr = Row->Attribute("subscription");
- _RosterInsertListItem(jid, name, group, subscr, true);
- }
- }
-
- OnChangeStatus();
- }
-};
-
-INT_PTR __cdecl CJabberProto::OnMenuHandleRosterControl(WPARAM, LPARAM)
-{
- if (m_hwndRosterEditor)
- SetForegroundWindow(m_hwndRosterEditor->GetHwnd());
- else {
- m_hwndRosterEditor = new CRosterEditorDlg(this);
- m_hwndRosterEditor->Show();
- }
-
- return 0;
-}
-
-void CJabberProto::_RosterHandleGetRequest(const TiXmlElement *node, CJabberIqInfo*)
-{
- if (m_hwndRosterEditor)
- m_hwndRosterEditor->HandleNode(node);
-}
-
-void CJabberProto::JabberUpdateDialogs(BOOL)
-{
- if (m_hwndRosterEditor)
- m_hwndRosterEditor->OnChangeStatus();
-}
+/*
+
+Jabber Protocol Plugin for Miranda NG
+
+Copyright (c) 2002-04 Santithorn Bunchua
+Copyright (c) 2005-12 George Hazan
+Copyright (C) 2012-23 Miranda NG team
+
+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; either version 2
+of the License, or (at your option) any later version.
+
+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, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "stdafx.h"
+
+#include <io.h>
+
+//////////////////////////////////////////////////////////////////////////
+// roster editor
+//
+
+enum
+{
+ RRA_FILLLIST = 0,
+ RRA_SYNCROSTER,
+ RRA_SYNCDONE
+};
+
+struct ROSTEREDITDAT
+{
+ HWND hList;
+ int index;
+ int subindex;
+};
+
+static void _RosterItemEditEnd(HWND hEditor, ROSTEREDITDAT *edat, BOOL bCancel)
+{
+ if (!bCancel) {
+ int len = GetWindowTextLength(hEditor) + 1;
+ wchar_t *buff = (wchar_t*)mir_alloc(len*sizeof(wchar_t));
+ if (buff) {
+ GetWindowText(hEditor, buff, len);
+ ListView_SetItemText(edat->hList, edat->index, edat->subindex, buff);
+ }
+ mir_free(buff);
+ }
+ DestroyWindow(hEditor);
+}
+
+static LRESULT CALLBACK _RosterItemNewEditProc(HWND hEditor, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ ROSTEREDITDAT * edat = (ROSTEREDITDAT *)GetWindowLongPtr(hEditor, GWLP_USERDATA);
+ if (!edat) return 0;
+ switch (msg) {
+ case WM_KEYDOWN:
+ switch (wParam) {
+ case VK_RETURN:
+ _RosterItemEditEnd(hEditor, edat, FALSE);
+ return 0;
+ case VK_ESCAPE:
+ _RosterItemEditEnd(hEditor, edat, TRUE);
+ return 0;
+ }
+ break;
+
+ case WM_GETDLGCODE:
+ if (lParam) {
+ MSG *msg2 = (MSG*)lParam;
+ if (msg2->message == WM_KEYDOWN && msg2->wParam == VK_TAB) return 0;
+ if (msg2->message == WM_CHAR && msg2->wParam == '\t') return 0;
+ }
+ return DLGC_WANTMESSAGE;
+
+ case WM_KILLFOCUS:
+ _RosterItemEditEnd(hEditor, edat, FALSE);
+ return 0;
+
+ case WM_DESTROY:
+ SetWindowLongPtr(hEditor, GWLP_USERDATA, (LONG_PTR)0);
+ free(edat);
+ return 0;
+ }
+
+ return mir_callNextSubclass(hEditor, _RosterItemNewEditProc, msg, wParam, lParam);
+}
+
+static LRESULT CALLBACK _RosterNewListProc(HWND hList, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg == WM_MOUSEWHEEL || msg == WM_NCLBUTTONDOWN || msg == WM_NCRBUTTONDOWN)
+ SetFocus(hList);
+
+ if (msg == WM_LBUTTONDOWN) {
+ POINT pt;
+ GetCursorPos(&pt);
+ ScreenToClient(hList, &pt);
+
+ LVHITTESTINFO lvhti = { 0 };
+ lvhti.pt = pt;
+ ListView_SubItemHitTest(hList, &lvhti);
+ if (lvhti.flags&LVHT_ONITEM && lvhti.iSubItem != 0) {
+ RECT rc;
+ wchar_t buff[260];
+ ListView_GetSubItemRect(hList, lvhti.iItem, lvhti.iSubItem, LVIR_BOUNDS, &rc);
+ ListView_GetItemText(hList, lvhti.iItem, lvhti.iSubItem, buff, _countof(buff));
+ HWND hEditor = CreateWindow(TEXT("EDIT"), buff, WS_CHILD | ES_AUTOHSCROLL, rc.left + 3, rc.top + 2, rc.right - rc.left - 3, rc.bottom - rc.top - 3, hList, nullptr, g_plugin.getInst(), nullptr);
+ SendMessage(hEditor, WM_SETFONT, (WPARAM)SendMessage(hList, WM_GETFONT, 0, 0), 0);
+ ShowWindow(hEditor, SW_SHOW);
+ SetWindowText(hEditor, buff);
+ ClientToScreen(hList, &pt);
+ ScreenToClient(hEditor, &pt);
+ mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
+ mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
+
+ ROSTEREDITDAT * edat = (ROSTEREDITDAT *)malloc(sizeof(ROSTEREDITDAT));
+ mir_subclassWindow(hEditor, _RosterItemNewEditProc);
+ edat->hList = hList;
+ edat->index = lvhti.iItem;
+ edat->subindex = lvhti.iSubItem;
+ SetWindowLongPtr(hEditor, GWLP_USERDATA, (LONG_PTR)edat);
+ }
+ }
+ return mir_callNextSubclass(hList, _RosterNewListProc, msg, wParam, lParam);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberRosterOptDlgProc - advanced options dialog procedure
+
+class CRosterEditorDlg : public CJabberDlgBase
+{
+ friend struct CJabberProto;
+ typedef CJabberDlgBase CSuper;
+
+ uint8_t m_bRRAction;
+ BOOL m_bReadyToDownload = true;
+ BOOL m_bReadyToUpload = false;
+
+ void _RosterSendRequest(uint8_t rrAction)
+ {
+ m_bRRAction = rrAction;
+
+ m_proto->m_ThreadInfo->send(
+ XmlNodeIq(m_proto->AddIQ(&CJabberProto::_RosterHandleGetRequest, JABBER_IQ_TYPE_GET))
+ << XCHILDNS("query", JABBER_FEAT_IQ_ROSTER));
+ }
+
+ int _RosterInsertListItem(const char *jid, const char *nick, const char *group, const char *subscr, bool bChecked)
+ {
+ Utf2T wszJid(jid);
+ LVITEM item = { 0 };
+ item.mask = LVIF_TEXT | LVIF_STATE;
+ item.iItem = m_list.GetItemCount();
+ item.pszText = wszJid;
+
+ int index = m_list.InsertItem(&item);
+ if (index < 0)
+ return index;
+
+ m_list.SetCheckState(index, bChecked);
+
+ m_list.SetItemText(index, 1, Utf2T(nick));
+ m_list.SetItemText(index, 2, Utf2T(group));
+ m_list.SetItemText(index, 3, TranslateW(Utf2T(subscr)));
+ return index;
+ }
+
+ void _RosterListClear()
+ {
+ m_list.DeleteAllItems();
+ while (m_list.GetColumnWidth(0) > 0)
+ m_list.DeleteColumn(0);
+
+ LV_COLUMN column = { 0 };
+ column.mask = LVCF_TEXT;
+
+ column.pszText = TranslateT("JID");
+ m_list.InsertColumn(1, &column);
+
+ column.pszText = TranslateT("Nickname");
+ m_list.InsertColumn(2, &column);
+
+ column.pszText = TranslateT("Group");
+ m_list.InsertColumn(3, &column);
+
+ column.pszText = TranslateT("Subscription");
+ m_list.InsertColumn(4, &column);
+
+ RECT rc;
+ GetClientRect(m_list.GetHwnd(), &rc);
+ ResizeColumns(rc.right - rc.left);
+ }
+
+ void ResizeColumns(int width)
+ {
+ m_list.SetColumnWidth(0, width * 40 / 100);
+ m_list.SetColumnWidth(1, width * 25 / 100);
+ m_list.SetColumnWidth(2, width * 20 / 100);
+ m_list.SetColumnWidth(3, width * 12 / 100);
+ }
+
+ void OnChangeStatus()
+ {
+ int count = m_list.GetItemCount();
+ btnDownload.Enable(m_proto->m_bJabberOnline);
+ btnUpload.Enable(count && m_proto->m_bJabberOnline);
+ btnExport.Enable(count > 0);
+ }
+
+ CCtrlButton btnDownload, btnUpload, btnExport, btnImport;
+ CCtrlListView m_list;
+
+public:
+ CRosterEditorDlg(CJabberProto *m_proto) :
+ CSuper(m_proto, IDD_ROSTER_EDITOR),
+ m_list(this, IDC_ROSTER),
+ btnExport(this, IDC_EXPORT),
+ btnImport(this, IDC_IMPORT),
+ btnUpload(this, IDC_UPLOAD),
+ btnDownload(this, IDC_DOWNLOAD)
+ {
+ SetMinSize(550, 390);
+
+ btnExport.OnClick = Callback(this, &CRosterEditorDlg::onClick_Export);
+ btnImport.OnClick = Callback(this, &CRosterEditorDlg::onClick_Import);
+ btnUpload.OnClick = Callback(this, &CRosterEditorDlg::onClick_Upload);
+ btnDownload.OnClick = Callback(this, &CRosterEditorDlg::onClick_Download);
+ }
+
+ bool OnInitDialog() override
+ {
+ SetWindowTextW(m_hwnd, CMStringW(FORMAT, L"%s: %s", TranslateT("Roster Editor"), m_proto->m_tszUserName));
+
+ Window_SetIcon_IcoLib(m_hwnd, g_plugin.getIconHandle(IDI_AGENTS));
+
+ Utils_RestoreWindowPosition(m_hwnd, 0, m_proto->m_szModuleName, "rosterCtrlWnd_");
+
+ m_list.SetExtendedListViewStyle(LVS_EX_CHECKBOXES | LVS_EX_BORDERSELECT | LVS_EX_GRIDLINES);
+ mir_subclassWindow(m_list.GetHwnd(), _RosterNewListProc);
+ _RosterListClear();
+ OnChangeStatus();
+ return true;
+ }
+
+ void OnDestroy() override
+ {
+ m_proto->m_hwndRosterEditor = nullptr;
+ Utils_SaveWindowPosition(m_hwnd, 0, m_proto->m_szModuleName, "rosterCtrlWnd_");
+ Window_FreeIcon_IcoLib(m_hwnd);
+ }
+
+ int Resizer(UTILRESIZECONTROL *urc) override
+ {
+ switch (urc->wId) {
+ case IDC_HEADERBAR:
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORX_WIDTH;
+ case IDC_ROSTER:
+ ResizeColumns(urc->rcItem.right - urc->rcItem.left + urc->dlgNewSize.cx - urc->dlgOriginalSize.cx);
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORY_HEIGHT | RD_ANCHORX_WIDTH;
+ case IDC_DOWNLOAD:
+ case IDC_UPLOAD:
+ return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM;
+ case IDC_EXPORT:
+ case IDC_IMPORT:
+ return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM;
+ }
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP;
+ }
+
+ void HandleNode(const TiXmlElement *node)
+ {
+ if (m_bRRAction == RRA_FILLLIST) {
+ _RosterListClear();
+ auto *query = XmlFirstChild(node, "query");
+ if (query == nullptr) return;
+
+ for (auto *item : TiXmlFilter(query, "item")) {
+ const char *jid = XmlGetAttr(item, "jid");
+ if (jid == nullptr)
+ continue;
+
+ const char *name = XmlGetAttr(item, "name");
+ const char *subscription = XmlGetAttr(item, "subscription");
+ const char *group = XmlGetChildText(item, "group");
+ _RosterInsertListItem(jid, name, group, subscription, true);
+ }
+
+ // now it is require to process whole contact list to add not in roster contacts
+ for (auto &hContact : m_proto->AccContacts()) {
+ ptrW tszJid(m_proto->getWStringA(hContact, "jid"));
+ if (tszJid == nullptr)
+ continue;
+
+ LVFINDINFO lvfi = { 0 };
+ lvfi.flags = LVFI_STRING;
+ lvfi.psz = tszJid;
+ if (m_list.FindItem(-1, &lvfi) == -1) {
+ ptrA tszName(db_get_utfa(hContact, "CList", "MyHandle"));
+ ptrA tszGroup(db_get_utfa(hContact, "CList", "Group"));
+ _RosterInsertListItem(T2Utf(tszJid), tszName, tszGroup, nullptr, false);
+ }
+ }
+ m_bReadyToDownload = false;
+ m_bReadyToUpload = true;
+ btnDownload.SetText(TranslateT("Download"));
+ btnUpload.SetText(TranslateT("Upload"));
+ OnChangeStatus();
+ return;
+ }
+
+ if (m_bRRAction == RRA_SYNCROSTER) {
+ btnUpload.SetText(TranslateT("Uploading..."));
+ auto *queryRoster = XmlFirstChild(node, "query");
+ if (!queryRoster)
+ return;
+
+ int ListItemCount = m_list.GetItemCount();
+ for (int index = 0; index < ListItemCount; index++) {
+ wchar_t jid[JABBER_MAX_JID_LEN] = L"";
+ wchar_t name[260];
+ wchar_t group[260];
+ wchar_t subscr[260];
+ m_list.GetItemText(index, 0, jid, _countof(jid));
+ m_list.GetItemText(index, 1, name, _countof(name));
+ m_list.GetItemText(index, 2, group, _countof(group));
+ m_list.GetItemText(index, 3, subscr, _countof(subscr));
+
+ T2Utf szJid(jid), szName(name), szGroup(group), szSubscr(subscr);
+ auto *itemRoster = XmlGetChildByTag(queryRoster, "item", "jid", szJid);
+ bool bRemove = !m_list.GetCheckState(index);
+ if (itemRoster && bRemove) { // delete item
+ XmlNodeIq iq(m_proto->AddIQ(&CJabberProto::_RosterHandleGetRequest, JABBER_IQ_TYPE_SET));
+ iq << XCHILDNS("query", JABBER_FEAT_IQ_ROSTER) << XCHILD("item") << XATTR("jid", szJid) << XATTR("subscription", "remove");
+ m_proto->m_ThreadInfo->send(iq);
+ }
+ else if (!bRemove) {
+ bool bPushed = itemRoster != 0;
+ const char *rosterName = 0, *rosterGroup = 0;
+ if (!bPushed) {
+ rosterName = XmlGetAttr(itemRoster, "name");
+ if ((rosterName != nullptr || name[0] != 0) && mir_strcmpi(rosterName, szName))
+ bPushed = true;
+ if (!bPushed) {
+ auto *szSub = XmlGetAttr(itemRoster, "subscription");
+ if ((szSub != nullptr || subscr[0] != 0) && mir_strcmpi(szSub, szSubscr))
+ bPushed = true;
+ }
+ if (!bPushed) {
+ rosterGroup = XmlGetChildText(itemRoster, "group");
+ if (rosterGroup != nullptr && mir_strcmpi(rosterGroup, szGroup))
+ bPushed = true;
+ }
+ }
+ if (bPushed) {
+ XmlNodeIq iq(m_proto->AddIQ(&CJabberProto::_RosterHandleGetRequest, JABBER_IQ_TYPE_SET));
+ auto *item = iq << XCHILDNS("query", JABBER_FEAT_IQ_ROSTER) << XCHILD("item");
+ if (rosterGroup || mir_strlen(szGroup))
+ item << XCHILD("group", szGroup);
+ if (rosterName || mir_strlen(szName))
+ item << XATTR("name", szName);
+ item << XATTR("jid", szJid) << XATTR("subscription", subscr[0] ? szSubscr : "none");
+ m_proto->m_ThreadInfo->send(iq);
+ }
+ }
+ }
+ m_bRRAction = RRA_SYNCDONE;
+ _RosterSendRequest(RRA_FILLLIST);
+ return;
+ }
+
+ btnUpload.SetText(TranslateT("Upload"));
+ onClick_Download(nullptr);
+ };
+
+ void onClick_Download(CCtrlButton*)
+ {
+ m_bReadyToUpload = m_bReadyToDownload = false;
+ OnChangeStatus();
+ btnDownload.SetText(TranslateT("Downloading..."));
+ _RosterSendRequest(RRA_FILLLIST);
+ }
+
+ void onClick_Upload(CCtrlButton*)
+ {
+ m_bReadyToUpload = false;
+ OnChangeStatus();
+ btnUpload.SetText(TranslateT("Connecting..."));
+ _RosterSendRequest(RRA_SYNCROSTER);
+ }
+
+ void onClick_Export(CCtrlButton*)
+ {
+ wchar_t filename[MAX_PATH] = { 0 };
+
+ wchar_t filter[MAX_PATH];
+ mir_snwprintf(filter, L"%s (*.xml)%c*.xml%c%c", TranslateT("XML (UTF-8 encoded)"), 0, 0, 0);
+ OPENFILENAME ofn = {};
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = m_hwnd;
+ ofn.lpstrFilter = filter;
+ ofn.lpstrFile = filename;
+ ofn.Flags = OFN_HIDEREADONLY;
+ ofn.nMaxFile = _countof(filename);
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = L"xml";
+ if (!GetSaveFileNameW(&ofn))
+ return;
+
+ FILE * fp = _wfopen(filename, L"wb");
+ if (!fp)
+ return;
+
+ int ListItemCount = m_list.GetItemCount();
+
+ XmlNode root("Roster");
+
+ for (int index = 0; index < ListItemCount; index++) {
+ wchar_t jid[JABBER_MAX_JID_LEN] = L"";
+ wchar_t name[260] = L"";
+ wchar_t group[260] = L"";
+ wchar_t subscr[260] = L"";
+ m_list.GetItemText(index, 0, jid, _countof(jid));
+ m_list.GetItemText(index, 1, name, _countof(name));
+ m_list.GetItemText(index, 2, group, _countof(group));
+ m_list.GetItemText(index, 3, subscr, _countof(subscr));
+ root << XCHILD("Item") << XATTR("jid", T2Utf(jid)) << XATTR("name", T2Utf(name)) << XATTR("group", T2Utf(group)) << XATTR("subscription", T2Utf(subscr));
+ }
+
+ tinyxml2::XMLPrinter printer(fp);
+ root.Print(&printer);
+ fclose(fp);
+ }
+
+ void onClick_Import(CCtrlButton*)
+ {
+ wchar_t filename[MAX_PATH] = {};
+
+ OPENFILENAME ofn = { 0 };
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = m_hwnd;
+ ofn.hInstance = nullptr;
+ ofn.lpstrFilter = L"XML (UTF-8 encoded)(*.xml)\0*.xml\0\0";
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.lpstrFile = filename;
+ ofn.nMaxFile = _countof(filename);
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = L"xml";
+ if (!GetOpenFileNameW(&ofn))
+ return;
+
+ FILE * fp = _wfopen(filename, L"rb");
+ if (!fp)
+ return;
+
+ TiXmlDocument doc;
+ int ret = doc.LoadFile(fp);
+ fclose(fp);
+ if (ret != 0)
+ return;
+
+ _RosterListClear();
+
+ const TiXmlElement *Table = TiXmlConst(&doc)["Workbook"]["Worksheet"]["Table"].ToElement();
+ if (Table) {
+ for (auto *Row : TiXmlFilter(Table, "Row")) {
+ bool bAdd = false;
+ const char *jid = nullptr;
+ const char *name = nullptr;
+ const char *group = nullptr;
+ const char *subscr = nullptr;
+ auto *Cell = XmlFirstChild(Row, "Cell");
+ auto *Data = XmlFirstChild(Cell, "Data");
+ if (Data) {
+ if (!mir_strcmpi(Data->GetText(), "+"))
+ bAdd = true;
+ else if (mir_strcmpi(Data->GetText(), "-"))
+ continue;
+
+ Cell = Cell->NextSiblingElement("Cell");
+ if (Cell) Data = XmlFirstChild(Cell, "Data");
+ else Data = nullptr;
+ if (Data) {
+ jid = Data->GetText();
+ if (!jid || mir_strlen(jid) == 0)
+ continue;
+ }
+
+ Cell = Cell->NextSiblingElement("Cell");
+ if (Cell) Data = XmlFirstChild(Cell, "Data");
+ else Data = nullptr;
+ if (Data) name = Data->GetText();
+
+ Cell = Cell->NextSiblingElement("Cell");
+ if (Cell) Data = XmlFirstChild(Cell, "Data");
+ else Data = nullptr;
+ if (Data) group = Data->GetText();
+
+ Cell = Cell->NextSiblingElement("Cell");
+ if (Cell) Data = XmlFirstChild(Cell, "Data");
+ else Data = nullptr;
+ if (Data) subscr = Data->GetText();
+ }
+ _RosterInsertListItem(jid, name, group, subscr, bAdd);
+ }
+ }
+ else if (Table = TiXmlConst(&doc)["Roster"].ToElement()) {
+ for (auto *Row : TiXmlFilter(Table, "Item")) {
+ auto *jid = Row->Attribute("jid");
+ auto *name = Row->Attribute("name");
+ auto *group = Row->Attribute("group");
+ auto *subscr = Row->Attribute("subscription");
+ _RosterInsertListItem(jid, name, group, subscr, true);
+ }
+ }
+
+ OnChangeStatus();
+ }
+};
+
+INT_PTR __cdecl CJabberProto::OnMenuHandleRosterControl(WPARAM, LPARAM)
+{
+ if (m_hwndRosterEditor)
+ SetForegroundWindow(m_hwndRosterEditor->GetHwnd());
+ else {
+ m_hwndRosterEditor = new CRosterEditorDlg(this);
+ m_hwndRosterEditor->Show();
+ }
+
+ return 0;
+}
+
+void CJabberProto::_RosterHandleGetRequest(const TiXmlElement *node, CJabberIqInfo*)
+{
+ if (m_hwndRosterEditor)
+ m_hwndRosterEditor->HandleNode(node);
+}
+
+void CJabberProto::JabberUpdateDialogs(BOOL)
+{
+ if (m_hwndRosterEditor)
+ m_hwndRosterEditor->OnChangeStatus();
+}
diff --git a/protocols/JabberG/src/jabber_search.cpp b/protocols/JabberG/src/jabber_search.cpp
index 8beaf9fb7b..5102211399 100644
--- a/protocols/JabberG/src/jabber_search.cpp
+++ b/protocols/JabberG/src/jabber_search.cpp
@@ -1,765 +1,765 @@
-/*
-
-Jabber Protocol Plugin for Miranda NG
-
-Copyright (c) 2002-04 Santithorn Bunchua
-Copyright (c) 2005-12 George Hazan
-Copyright (c) 2007 Artem Shpynov
-Copyright (C) 2012-22 Miranda NG team
-
-Module implements a search according to XEP-0055: Jabber Search
-http://www.xmpp.org/extensions/xep-0055.html
-
-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; either version 2
-of the License, or (at your option) any later version.
-
-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, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-
-#include "stdafx.h"
-#include <CommCtrl.h>
-#include "jabber_iq.h"
-#include "jabber_caps.h"
-
-///////////////////////////////////////////////////////////////////////////////
-// Subclassing of IDC_FRAME to implement more user-friendly fields scrolling
-
-static int JabberSearchFrameProc(HWND hwnd, int msg, WPARAM wParam, LPARAM lParam)
-{
- if (msg == WM_COMMAND && lParam != 0) {
- HWND hwndDlg = GetParent(hwnd);
- JabberSearchData *dat = (JabberSearchData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
- if (dat && lParam) {
- int pos = dat->curPos;
- RECT MineRect;
- RECT FrameRect;
- GetWindowRect(GetDlgItem(hwndDlg, IDC_FRAME), &FrameRect);
- GetWindowRect((HWND)lParam, &MineRect);
- if (MineRect.top - 10 < FrameRect.top) {
- pos = dat->curPos + (MineRect.top - 14 - FrameRect.top);
- if (pos < 0) pos = 0;
- }
- else if (MineRect.bottom > FrameRect.bottom) {
- pos = dat->curPos + (MineRect.bottom - FrameRect.bottom);
- if (dat->frameHeight + pos > dat->CurrentHeight)
- pos = dat->CurrentHeight - dat->frameHeight;
- }
- if (pos != dat->curPos) {
- ScrollWindow(GetDlgItem(hwndDlg, IDC_FRAME), 0, dat->curPos - pos, nullptr, &(dat->frameRect));
- SetScrollPos(GetDlgItem(hwndDlg, IDC_VSCROLL), SB_CTL, pos, TRUE);
- RECT Invalid = dat->frameRect;
- if (dat->curPos - pos > 0)
- Invalid.bottom = Invalid.top + (dat->curPos - pos);
- else
- Invalid.top = Invalid.bottom + (dat->curPos - pos);
-
- RedrawWindow(GetDlgItem(hwndDlg, IDC_FRAME), nullptr, nullptr, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
- dat->curPos = pos;
- }
- }
-
- // Transmit focus set notification to parent window
- if (HIWORD(wParam) == EN_SETFOCUS)
- PostMessage(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndDlg);
- }
-
- if (msg == WM_PAINT) {
- PAINTSTRUCT ps;
- HDC hdc = BeginPaint(hwnd, &ps);
- FillRect(hdc, &(ps.rcPaint), GetSysColorBrush(COLOR_BTNFACE));
- EndPaint(hwnd, &ps);
- }
-
- return DefWindowProc(hwnd, msg, wParam, lParam);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Add Search field to form
-
-static int JabberSearchAddField(HWND hwndDlg, Data* FieldDat)
-{
- if (!FieldDat || !FieldDat->Label || !FieldDat->Var)
- return FALSE;
-
- HFONT hFont = (HFONT)SendMessage(hwndDlg, WM_GETFONT, 0, 0);
- HWND hwndParent = GetDlgItem(hwndDlg, IDC_FRAME);
- LONG_PTR frameExStyle = GetWindowLongPtr(hwndParent, GWL_EXSTYLE);
- frameExStyle |= WS_EX_CONTROLPARENT;
- SetWindowLongPtr(hwndParent, GWL_EXSTYLE, frameExStyle);
- SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FRAME), GWLP_WNDPROC, (LONG_PTR)JabberSearchFrameProc);
-
- int CornerX = 1;
- int CornerY = 1;
- RECT rect;
- GetClientRect(hwndParent, &rect);
- int width = rect.right - 5 - CornerX;
-
- int Order = (FieldDat->bHidden) ? -1 : FieldDat->Order;
-
- HWND hwndLabel = CreateWindowEx(0, L"STATIC", (const wchar_t *)TranslateW(FieldDat->Label), WS_CHILD, CornerX, CornerY + Order * 40, width, 13, hwndParent, nullptr, g_plugin.getInst(), nullptr);
- HWND hwndVar = CreateWindowEx(0 | WS_EX_CLIENTEDGE, L"EDIT", FieldDat->defValue, WS_CHILD | WS_TABSTOP, CornerX + 5, CornerY + Order * 40 + 14, width, 20, hwndParent, nullptr, g_plugin.getInst(), nullptr);
- SendMessage(hwndLabel, WM_SETFONT, (WPARAM)hFont, 0);
- SendMessage(hwndVar, WM_SETFONT, (WPARAM)hFont, 0);
- if (!FieldDat->bHidden) {
- ShowWindow(hwndLabel, SW_SHOW);
- ShowWindow(hwndVar, SW_SHOW);
- EnableWindow(hwndLabel, !FieldDat->bReadOnly);
- SendMessage(hwndVar, EM_SETREADONLY, (WPARAM)FieldDat->bReadOnly, 0);
- }
-
- // remade list
- // reallocation
- JabberSearchData *dat = (JabberSearchData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
- if (dat) {
- dat->pJSInf = (JabberSearchFieldsInfo*)realloc(dat->pJSInf, sizeof(JabberSearchFieldsInfo)*(dat->nJSInfCount + 1));
- dat->pJSInf[dat->nJSInfCount].hwndCaptionItem = hwndLabel;
- dat->pJSInf[dat->nJSInfCount].hwndValueItem = hwndVar;
- dat->pJSInf[dat->nJSInfCount].szFieldCaption = wcsdup(FieldDat->Label);
- dat->pJSInf[dat->nJSInfCount].szFieldName = wcsdup(FieldDat->Var);
- dat->nJSInfCount++;
- }
- return CornerY + Order * 40 + 14 + 20;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Available search field request result handler (XEP-0055. Examples 2, 7)
-
-void CJabberProto::OnIqResultGetSearchFields(const TiXmlElement *iqNode, CJabberIqInfo*)
-{
- if (!searchHandleDlg)
- return;
-
- const char *type = XmlGetAttr(iqNode, "type");
- if (type == nullptr)
- return;
-
- if (!mir_strcmp(type, "result")) {
- auto *queryNode = XmlFirstChild(iqNode, "query");
- auto *xNode = XmlGetChildByTag(queryNode, "x", "xmlns", JABBER_FEAT_DATA_FORMS);
-
- ShowWindow(searchHandleDlg, SW_HIDE);
- if (xNode) {
- // 1. Form
- PostMessage(searchHandleDlg, WM_USER + 11, (WPARAM)xNode, 0);
- auto *xcNode = XmlFirstChild(xNode, "instructions");
- if (xcNode)
- SetDlgItemTextUtf(searchHandleDlg, IDC_INSTRUCTIONS, xcNode->GetText());
- }
- else {
- int Order = 0;
- for (auto *chNode : TiXmlEnum(queryNode)) {
- if (!mir_strcmpi(chNode->Name(), "instructions") && chNode->GetText())
- SetDlgItemText(searchHandleDlg, IDC_INSTRUCTIONS, TranslateW(Utf2T(chNode->GetText())));
- else if (chNode->Name()) {
- Data *MyData = (Data*)malloc(sizeof(Data));
- memset(MyData, 0, sizeof(Data));
-
- MyData->Label = mir_utf8decodeW(chNode->Name());
- MyData->Var = mir_utf8decodeW(chNode->Name());
- MyData->defValue = mir_utf8decodeW(chNode->GetText());
- MyData->Order = Order;
- if (MyData->defValue)
- MyData->bReadOnly = true;
- PostMessage(searchHandleDlg, WM_USER + 10, FALSE, (LPARAM)MyData);
- Order++;
- }
- }
- }
-
- const char *szFrom = XmlGetAttr(iqNode, "from");
- if (szFrom)
- SearchAddToRecent(szFrom, searchHandleDlg);
- PostMessage(searchHandleDlg, WM_USER + 10, 0, 0);
- ShowWindow(searchHandleDlg, SW_SHOW);
- }
- else if (!mir_strcmp(type, "error")) {
- const char *code = "";
- const char *description = "";
- auto *errorNode = XmlFirstChild(iqNode, "error");
- if (errorNode) {
- code = XmlGetAttr(errorNode, "code");
- description = errorNode->GetText();
- }
-
- char buff[255];
- mir_snprintf(buff, TranslateU("Error %s %s\r\nPlease select other server"), code, description);
- SetDlgItemTextUtf(searchHandleDlg, IDC_INSTRUCTIONS, buff);
- }
- else SetDlgItemText(searchHandleDlg, IDC_INSTRUCTIONS, TranslateT("Error: unknown reply received\r\nPlease select other server"));
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-// Return results to search dialog
-// The pmFields is the pointer to map of <field Name, field Label> Not unical but ordered
-// This can help to made result parser routines more simple
-
-static char *nickfields[] = { "nick", "nickname", "fullname", "name", "given", "first", "jid", nullptr };
-
-static int TCharKeyCmp(const char *p1, const char *p2)
-{
- return mir_strcmpi(p1, p2);
-}
-
-static void SearchReturnResults(CJabberProto *ppro, HANDLE id, LIST<UNIQUE_MAP> &plUsersInfo, UNIQUE_MAP &pmAllFields)
-{
- LIST<char> ListOfNonEmptyFields(20, TCharKeyCmp);
- LIST<char> ListOfFields(20);
-
- // lets fill the ListOfNonEmptyFields but in users order
- for (auto &pmUserData : plUsersInfo) {
- int nUserFields = pmUserData->getCount();
- for (int j = 0; j < nUserFields; j++) {
- char *var = pmUserData->getKeyName(j);
- if (var && ListOfNonEmptyFields.getIndex(var) < 0)
- ListOfNonEmptyFields.insert(var);
- }
- }
-
- // now fill the ListOfFields but order is from pmAllFields
- int nAllCount = pmAllFields.getCount();
- for (int i = 0; i < nAllCount; i++) {
- char *var = pmAllFields.getUnOrderedKeyName(i);
- if (var && ListOfNonEmptyFields.getIndex(var) < 0)
- continue;
- ListOfFields.insert(var);
- }
-
- // now lets transfer field names
- int nFieldCount = ListOfFields.getCount();
-
- CUSTOMSEARCHRESULTS Results = { 0 };
- Results.nSize = sizeof(Results);
- Results.pszFields = (wchar_t**)mir_alloc(sizeof(wchar_t*)*nFieldCount);
- Results.nFieldCount = nFieldCount;
-
- // Sending Columns Titles
- for (int i = 0; i < nFieldCount; i++) {
- char *var = ListOfFields[i];
- if (var)
- Results.pszFields[i] = mir_utf8decodeW(pmAllFields[var]);
- }
-
- Results.psr.cbSize = 0; // sending column names
- ppro->ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SEARCHRESULT, id, (LPARAM)&Results);
- for (int i = 0; i < nFieldCount; i++)
- replaceStrW(Results.pszFields[i], nullptr);
-
- // Sending Users Data
- Results.psr.cbSize = sizeof(Results.psr);
-
- for (auto &pmUserData : plUsersInfo) {
- for (int j = 0; j < nFieldCount; j++) {
- char *var = ListOfFields[j];
- char *value = pmUserData->operator [](var);
- Results.pszFields[j] = value ? mir_utf8decodeW(value) : mir_wstrdup(L" ");
- if (!mir_strcmpi(var, "jid") && value)
- Results.psr.id.w = Results.pszFields[j];
- }
-
- const char *nick = nullptr;
- for (int k = 0; k < _countof(nickfields) && !nick; k++)
- nick = pmUserData->operator [](nickfields[k]);
-
- if (nick) {
- Utf2T wszNick(nick);
- wchar_t buff[200];
- if (mir_wstrcmpi(wszNick, Results.psr.id.w))
- mir_snwprintf(buff, L"%s (%s)", wszNick.get(), Results.psr.id.w);
- else
- wcsncpy_s(buff, wszNick, _TRUNCATE);
-
- Results.psr.nick.w = buff;
- }
- else Results.psr.nick.w = L"";
- Results.psr.flags = PSR_UNICODE;
-
- ppro->ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SEARCHRESULT, id, (LPARAM)&Results);
- for (int i = 0; i < nFieldCount; i++)
- replaceStrW(Results.pszFields[i], nullptr);
- }
-
- mir_free(Results.pszFields);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Search field request result handler (XEP-0055. Examples 3, 8)
-
-void CJabberProto::OnIqResultAdvancedSearch(const TiXmlElement *iqNode, CJabberIqInfo*)
-{
- const char *type;
- int id;
-
- UNIQUE_MAP mColumnsNames(10);
- LIST<UNIQUE_MAP> SearchResults(2);
-
- if (((id = JabberGetPacketID(iqNode)) == -1) || ((type = XmlGetAttr(iqNode, "type")) == nullptr)) {
- ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)id);
- return;
- }
-
- if (!mir_strcmp(type, "result")) {
- auto *queryNode = XmlFirstChild(iqNode, "query");
- auto *xNode = XmlGetChildByTag(queryNode, "x", "xmlns", JABBER_FEAT_DATA_FORMS);
- if (xNode) {
- // 1. Form search results info
- for (auto *fieldNode : TiXmlFilter(XmlFirstChild(xNode, "reported"), "field")) {
- auto *var = XmlGetAttr(fieldNode, "var");
- if (var) {
- auto *label = XmlGetAttr(fieldNode, "label");
- mColumnsNames.insert(var, (label != nullptr) ? label : var);
- }
- }
-
- for (auto *itemNode : TiXmlFilter(xNode, "item")) {
- UNIQUE_MAP *pUserColumn = new UNIQUE_MAP(10);
- for (auto *fieldNode : TiXmlFilter(itemNode, "field")) {
- if (auto *var = XmlGetAttr(fieldNode, "var")) {
- if (auto *textNode = XmlFirstChild(fieldNode, "value")) {
- if (!mColumnsNames[var])
- mColumnsNames.insert(var, var);
- pUserColumn->insert(var, textNode->GetText());
- }
- }
- }
-
- SearchResults.insert(pUserColumn);
- }
- }
- else {
- // 2. Field list search results info
- for (auto *itemNode : TiXmlFilter(queryNode, "item")) {
- UNIQUE_MAP *pUserColumn = new UNIQUE_MAP(10);
-
- auto *jid = XmlGetAttr(itemNode, "jid");
- char *keyReturned;
- mColumnsNames.insertCopyKey("jid", "jid", &keyReturned);
- mColumnsNames.insert("jid", keyReturned);
- pUserColumn->insertCopyKey("jid", jid, nullptr);
-
- for (auto *child : TiXmlEnum(itemNode)) {
- const char *szColumnName = child->Name();
- if (szColumnName) {
- const char *pszChild = child->GetText();
- if (pszChild && *pszChild) {
- mColumnsNames.insertCopyKey(szColumnName, "", &keyReturned);
- mColumnsNames.insert(szColumnName, keyReturned);
- pUserColumn->insertCopyKey(szColumnName, pszChild, nullptr);
- }
- }
- }
-
- SearchResults.insert(pUserColumn);
- }
- }
- }
- else if (!mir_strcmp(type, "error")) {
- const char *code = "";
- const char *description = "";
- auto *errorNode = XmlFirstChild(iqNode, "error");
- if (errorNode) {
- code = XmlGetAttr(errorNode, "code");
- description = errorNode->GetText();
- }
-
- ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)id);
-
- char buff[255];
- mir_snprintf(buff, TranslateU("Error %s %s\r\nTry to specify more detailed"), code, description);
- if (searchHandleDlg)
- SetDlgItemTextUtf(searchHandleDlg, IDC_INSTRUCTIONS, buff);
- else
- MessageBox(nullptr, Utf2T(buff), TranslateT("Search error"), MB_OK | MB_ICONSTOP);
- return;
- }
-
- SearchReturnResults(this, (HANDLE)id, SearchResults, mColumnsNames);
-
- for (auto &it : SearchResults)
- delete ((UNIQUE_MAP*)it);
-
- //send success to finish searching
- ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)id);
-}
-
-static BOOL CALLBACK DeleteChildWindowsProc(HWND hwnd, LPARAM)
-{
- DestroyWindow(hwnd);
- return TRUE;
-}
-
-static void JabberSearchFreeData(HWND hwndDlg, JabberSearchData * dat)
-{
- if (!dat->fSearchRequestIsXForm && dat->nJSInfCount && dat->pJSInf) {
- for (int i = 0; i < dat->nJSInfCount; i++) {
- if (dat->pJSInf[i].hwndValueItem)
- DestroyWindow(dat->pJSInf[i].hwndValueItem);
- if (dat->pJSInf[i].hwndCaptionItem)
- DestroyWindow(dat->pJSInf[i].hwndCaptionItem);
- if (dat->pJSInf[i].szFieldCaption)
- free(dat->pJSInf[i].szFieldCaption);
- if (dat->pJSInf[i].szFieldName)
- free(dat->pJSInf[i].szFieldName);
- }
- free(dat->pJSInf);
- dat->pJSInf = nullptr;
- }
- else EnumChildWindows(GetDlgItem(hwndDlg, IDC_FRAME), DeleteChildWindowsProc, 0);
-
- SendDlgItemMessage(hwndDlg, IDC_FRAME, WM_SETFONT, (WPARAM)SendMessage(hwndDlg, WM_GETFONT, 0, 0), 0);
- dat->nJSInfCount = 0;
- ShowWindow(GetDlgItem(hwndDlg, IDC_VSCROLL), SW_HIDE);
- SetDlgItemText(hwndDlg, IDC_INSTRUCTIONS, TranslateT("Select/type search service URL above and press <Go>"));
-}
-
-static void JabberSearchRefreshFrameScroll(HWND hwndDlg, JabberSearchData *dat)
-{
- HWND hFrame = GetDlgItem(hwndDlg, IDC_FRAME);
- HWND hwndScroll = GetDlgItem(hwndDlg, IDC_VSCROLL);
- RECT rc;
- GetClientRect(hFrame, &rc);
- GetClientRect(hFrame, &dat->frameRect);
- dat->frameHeight = rc.bottom - rc.top;
- if (dat->frameHeight < dat->CurrentHeight) {
- ShowWindow(hwndScroll, SW_SHOW);
- EnableWindow(hwndScroll, TRUE);
- }
- else ShowWindow(hwndScroll, SW_HIDE);
-
- SetScrollRange(hwndScroll, SB_CTL, 0, dat->CurrentHeight - dat->frameHeight, FALSE);
-}
-
-int CJabberProto::SearchRenewFields(HWND hwndDlg, JabberSearchData *dat)
-{
- wchar_t szServerName[100];
- EnableWindow(GetDlgItem(hwndDlg, IDC_GO), FALSE);
- GetDlgItemText(hwndDlg, IDC_SERVER, szServerName, _countof(szServerName));
- dat->CurrentHeight = 0;
- dat->curPos = 0;
- SetScrollPos(GetDlgItem(hwndDlg, IDC_VSCROLL), SB_CTL, 0, FALSE);
-
- JabberSearchFreeData(hwndDlg, dat);
- JabberSearchRefreshFrameScroll(hwndDlg, dat);
-
- SetDlgItemText(hwndDlg, IDC_INSTRUCTIONS, m_bJabberOnline ? TranslateT("Please wait...\r\nConnecting search server...") : TranslateT("You have to be connected to server"));
-
- if (!m_bJabberOnline)
- return 0;
-
- searchHandleDlg = hwndDlg;
-
- CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultGetSearchFields, JABBER_IQ_TYPE_GET, T2Utf(szServerName));
- m_ThreadInfo->send(XmlNodeIq(pInfo) << XQUERY(JABBER_FEAT_JUD));
- return pInfo->GetIqId();
-}
-
-static void JabberSearchAddUrlToRecentCombo(HWND hwndDlg, const wchar_t *szAddr)
-{
- int lResult = SendDlgItemMessage(hwndDlg, IDC_SERVER, (UINT)CB_FINDSTRING, 0, (LPARAM)szAddr);
- if (lResult == -1)
- SendDlgItemMessage(hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, (LPARAM)szAddr);
-}
-
-void CJabberProto::SearchDeleteFromRecent(const char *szAddr, bool deleteLastFromDB)
-{
- // search in recent
- for (int i = 0; i < 10; i++) {
- char key[30];
- mir_snprintf(key, "RecentlySearched_%d", i);
- ptrA szValue(getUStringA(key));
- if (szValue == nullptr || mir_strcmpi(szAddr, szValue))
- continue;
-
- for (int j = i; j < 10; j++) {
- mir_snprintf(key, "RecentlySearched_%d", j + 1);
- szValue = getUStringA(key);
- if (szValue != nullptr) {
- mir_snprintf(key, "RecentlySearched_%d", j);
- setUString(0, key, szValue);
- }
- else {
- if (deleteLastFromDB) {
- mir_snprintf(key, "RecentlySearched_%d", j);
- delSetting(0, key);
- }
- break;
- }
- }
- break;
- }
-}
-
-void CJabberProto::SearchAddToRecent(const char *szAddr, HWND hwndDialog)
-{
- char key[30];
- SearchDeleteFromRecent(szAddr, true);
-
- for (int j = 9; j > 0; j--) {
- mir_snprintf(key, "RecentlySearched_%d", j - 1);
- ptrW szValue(getWStringA(key));
- if (szValue != nullptr) {
- mir_snprintf(key, "RecentlySearched_%d", j);
- setWString(0, key, szValue);
- }
- }
-
- mir_snprintf(key, "RecentlySearched_%d", 0);
- setUString(key, szAddr);
- if (hwndDialog)
- JabberSearchAddUrlToRecentCombo(hwndDialog, Utf2T(szAddr));
-}
-
-static INT_PTR CALLBACK JabberSearchAdvancedDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- JabberSearchData *dat = (JabberSearchData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
- switch (msg) {
- case WM_INITDIALOG:
- TranslateDialogDefault(hwndDlg);
- {
- dat = new JabberSearchData();
- dat->ppro = (CJabberProto *)lParam;
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
-
- /* Server Combo box */
- ptrA jud(dat->ppro->getStringA("Jud"));
- if (jud != nullptr) {
- SetDlgItemTextA(hwndDlg, IDC_SERVER, jud);
- SendDlgItemMessageA(hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, jud);
- }
-
- //TO DO: Add Transports here
- for (auto &it : dat->ppro->m_lstTransports)
- if (it != nullptr)
- JabberSearchAddUrlToRecentCombo(hwndDlg, Utf2T(it));
-
- for (int i = 0; i < 10; i++) {
- char key[30];
- mir_snprintf(key, "RecentlySearched_%d", i);
- ptrW szValue(dat->ppro->getWStringA(key));
- if (szValue != nullptr)
- JabberSearchAddUrlToRecentCombo(hwndDlg, szValue);
- }
-
- //TO DO: Add 4 recently used
- dat->lastRequestIq = dat->ppro->SearchRenewFields(hwndDlg, dat);
- }
- return TRUE;
-
- case WM_COMMAND:
- if (LOWORD(wParam) == IDC_SERVER) {
- switch (HIWORD(wParam)) {
- case CBN_SETFOCUS:
- PostMessage(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndDlg);
- return TRUE;
-
- case CBN_EDITCHANGE:
- EnableWindow(GetDlgItem(hwndDlg, IDC_GO), TRUE);
- return TRUE;
-
- case CBN_EDITUPDATE:
- JabberSearchFreeData(hwndDlg, dat);
- EnableWindow(GetDlgItem(hwndDlg, IDC_GO), TRUE);
- return TRUE;
-
- case CBN_SELENDOK:
- EnableWindow(GetDlgItem(hwndDlg, IDC_GO), TRUE);
- PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_GO, BN_CLICKED), 0);
- return TRUE;
- }
- }
- else if (LOWORD(wParam) == IDC_GO && HIWORD(wParam) == BN_CLICKED) {
- dat->ppro->SearchRenewFields(hwndDlg, dat);
- return TRUE;
- }
- break;
-
- case WM_SIZE:
- {
- //Resize IDC_FRAME to take full size
- RECT rcForm;
- GetWindowRect(hwndDlg, &rcForm);
- RECT rcFrame;
- GetWindowRect(GetDlgItem(hwndDlg, IDC_FRAME), &rcFrame);
- rcFrame.bottom = rcForm.bottom;
- SetWindowPos(GetDlgItem(hwndDlg, IDC_FRAME), nullptr, 0, 0, rcFrame.right - rcFrame.left, rcFrame.bottom - rcFrame.top, SWP_NOZORDER | SWP_NOMOVE);
- GetWindowRect(GetDlgItem(hwndDlg, IDC_VSCROLL), &rcForm);
- SetWindowPos(GetDlgItem(hwndDlg, IDC_VSCROLL), nullptr, 0, 0, rcForm.right - rcForm.left, rcFrame.bottom - rcFrame.top, SWP_NOZORDER | SWP_NOMOVE);
- JabberSearchRefreshFrameScroll(hwndDlg, dat);
- }
- return TRUE;
-
- case WM_USER + 11:
- {
- dat->fSearchRequestIsXForm = TRUE;
- if (dat->xNode) {
- dat->doc.DeleteNode(dat->xNode);
- dat->xNode = nullptr;
- }
- TiXmlElement *pNode = (TiXmlElement *)wParam;
- if (pNode) {
- dat->xNode = pNode->DeepClone(&dat->doc)->ToElement();
- JabberFormCreateUI(GetDlgItem(hwndDlg, IDC_FRAME), dat->xNode, &dat->CurrentHeight, TRUE);
- }
- ShowWindow(GetDlgItem(hwndDlg, IDC_FRAME), SW_SHOW);
- dat->nJSInfCount = 1;
- }
- return TRUE;
-
- case WM_USER + 10:
- {
- Data *MyDat = (Data *)lParam;
- if (MyDat) {
- dat->fSearchRequestIsXForm = (BOOL)wParam;
- dat->CurrentHeight = JabberSearchAddField(hwndDlg, MyDat);
- mir_free(MyDat->Label);
- mir_free(MyDat->Var);
- mir_free(MyDat->defValue);
- free(MyDat);
- }
- else {
- JabberSearchRefreshFrameScroll(hwndDlg, dat);
- ScrollWindow(GetDlgItem(hwndDlg, IDC_FRAME), 0, dat->curPos - 0, nullptr, &(dat->frameRect));
- SetScrollPos(GetDlgItem(hwndDlg, IDC_VSCROLL), SB_CTL, 0, FALSE);
- dat->curPos = 0;
- }
- }
- return TRUE;
-
- case WM_MOUSEWHEEL:
- {
- short zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
- if (zDelta) {
- int nScrollLines = 0;
- SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, (void *)&nScrollLines, 0);
- for (int i = 0; i < (nScrollLines + 1) / 2; i++)
- SendMessage(hwndDlg, WM_VSCROLL, (zDelta < 0) ? SB_LINEDOWN : SB_LINEUP, 0);
- }
- }
- return TRUE;
-
- case WM_VSCROLL:
- {
- int pos;
- if (dat != nullptr) {
- pos = dat->curPos;
- switch (LOWORD(wParam)) {
- case SB_LINEDOWN:
- pos += 10;
- break;
- case SB_LINEUP:
- pos -= 10;
- break;
- case SB_PAGEDOWN:
- pos += (dat->CurrentHeight - 10);
- break;
- case SB_PAGEUP:
- pos -= (dat->CurrentHeight - 10);
- break;
- case SB_THUMBTRACK:
- pos = HIWORD(wParam);
- break;
- }
- if (pos > (dat->CurrentHeight - dat->frameHeight))
- pos = dat->CurrentHeight - dat->frameHeight;
- if (pos < 0)
- pos = 0;
- if (dat->curPos != pos) {
- ScrollWindow(GetDlgItem(hwndDlg, IDC_FRAME), 0, dat->curPos - pos, nullptr, &(dat->frameRect));
- SetScrollPos(GetDlgItem(hwndDlg, IDC_VSCROLL), SB_CTL, pos, TRUE);
- RECT Invalid = dat->frameRect;
- if (dat->curPos - pos > 0)
- Invalid.bottom = Invalid.top + (dat->curPos - pos);
- else
- Invalid.top = Invalid.bottom + (dat->curPos - pos);
-
- RedrawWindow(GetDlgItem(hwndDlg, IDC_FRAME), nullptr, nullptr, RDW_UPDATENOW | RDW_ALLCHILDREN);
- dat->curPos = pos;
- }
- }
- }
- return TRUE;
-
- case WM_DESTROY:
- JabberSearchFreeData(hwndDlg, dat);
- JabberFormDestroyUI(GetDlgItem(hwndDlg, IDC_FRAME));
- delete dat;
- SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
- return TRUE;
- }
- return FALSE;
-}
-
-HWND CJabberProto::CreateExtendedSearchUI(HWND parent)
-{
- if (parent && g_plugin.getInst()) {
- ptrW szServer(getWStringA("LoginServer"));
- if (szServer == nullptr || mir_wstrcmpi(szServer, L"S.ms"))
- return CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_SEARCHUSER), parent, JabberSearchAdvancedDlgProc, (LPARAM)this);
- }
-
- return nullptr; // Failure
-}
-
-//////////////////////////////////////////////////////////////////////////
-// The function formats request to server
-
-HWND CJabberProto::SearchAdvanced(HWND hwndDlg)
-{
- if (!m_bJabberOnline || !hwndDlg)
- return nullptr; //error
-
- JabberSearchData *dat = (JabberSearchData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
- if (!dat)
- return nullptr; //error
-
- // check if server connected (at least one field exists)
- if (dat->nJSInfCount == 0)
- return nullptr;
-
- // formating request
- bool fRequestNotEmpty = false;
-
- // get server name
- wchar_t szServerName[100];
- GetDlgItemText(hwndDlg, IDC_SERVER, szServerName, _countof(szServerName));
-
- // formating query
- CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultAdvancedSearch, JABBER_IQ_TYPE_SET, T2Utf(szServerName));
- XmlNodeIq iq(pInfo);
- TiXmlElement *query = iq << XQUERY(JABBER_FEAT_JUD);
-
- if (m_tszSelectedLang)
- iq << XATTR("xml:lang", m_tszSelectedLang); // i'm sure :)
-
- // next can be 2 cases:
- // Forms: XEP-0055 Example 7
- if (dat->fSearchRequestIsXForm) {
- fRequestNotEmpty = true;
- JabberFormGetData(GetDlgItem(hwndDlg, IDC_FRAME), query, dat->xNode);
- }
- else { //and Simple fields: XEP-0055 Example 3
- for (int i = 0; i < dat->nJSInfCount; i++) {
- wchar_t szFieldValue[100];
- GetWindowText(dat->pJSInf[i].hwndValueItem, szFieldValue, _countof(szFieldValue));
- if (szFieldValue[0] != 0) {
- XmlAddChildA(query, T2Utf(dat->pJSInf[i].szFieldName).get(), T2Utf(szFieldValue).get());
- fRequestNotEmpty = true;
- }
- }
- }
-
- if (fRequestNotEmpty) {
- m_ThreadInfo->send(iq);
- return (HWND)pInfo->GetIqId();
- }
- return nullptr;
-}
+/*
+
+Jabber Protocol Plugin for Miranda NG
+
+Copyright (c) 2002-04 Santithorn Bunchua
+Copyright (c) 2005-12 George Hazan
+Copyright (c) 2007 Artem Shpynov
+Copyright (C) 2012-23 Miranda NG team
+
+Module implements a search according to XEP-0055: Jabber Search
+http://www.xmpp.org/extensions/xep-0055.html
+
+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; either version 2
+of the License, or (at your option) any later version.
+
+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, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "stdafx.h"
+#include <CommCtrl.h>
+#include "jabber_iq.h"
+#include "jabber_caps.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// Subclassing of IDC_FRAME to implement more user-friendly fields scrolling
+
+static int JabberSearchFrameProc(HWND hwnd, int msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg == WM_COMMAND && lParam != 0) {
+ HWND hwndDlg = GetParent(hwnd);
+ JabberSearchData *dat = (JabberSearchData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ if (dat && lParam) {
+ int pos = dat->curPos;
+ RECT MineRect;
+ RECT FrameRect;
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_FRAME), &FrameRect);
+ GetWindowRect((HWND)lParam, &MineRect);
+ if (MineRect.top - 10 < FrameRect.top) {
+ pos = dat->curPos + (MineRect.top - 14 - FrameRect.top);
+ if (pos < 0) pos = 0;
+ }
+ else if (MineRect.bottom > FrameRect.bottom) {
+ pos = dat->curPos + (MineRect.bottom - FrameRect.bottom);
+ if (dat->frameHeight + pos > dat->CurrentHeight)
+ pos = dat->CurrentHeight - dat->frameHeight;
+ }
+ if (pos != dat->curPos) {
+ ScrollWindow(GetDlgItem(hwndDlg, IDC_FRAME), 0, dat->curPos - pos, nullptr, &(dat->frameRect));
+ SetScrollPos(GetDlgItem(hwndDlg, IDC_VSCROLL), SB_CTL, pos, TRUE);
+ RECT Invalid = dat->frameRect;
+ if (dat->curPos - pos > 0)
+ Invalid.bottom = Invalid.top + (dat->curPos - pos);
+ else
+ Invalid.top = Invalid.bottom + (dat->curPos - pos);
+
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_FRAME), nullptr, nullptr, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
+ dat->curPos = pos;
+ }
+ }
+
+ // Transmit focus set notification to parent window
+ if (HIWORD(wParam) == EN_SETFOCUS)
+ PostMessage(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndDlg);
+ }
+
+ if (msg == WM_PAINT) {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hwnd, &ps);
+ FillRect(hdc, &(ps.rcPaint), GetSysColorBrush(COLOR_BTNFACE));
+ EndPaint(hwnd, &ps);
+ }
+
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Add Search field to form
+
+static int JabberSearchAddField(HWND hwndDlg, Data* FieldDat)
+{
+ if (!FieldDat || !FieldDat->Label || !FieldDat->Var)
+ return FALSE;
+
+ HFONT hFont = (HFONT)SendMessage(hwndDlg, WM_GETFONT, 0, 0);
+ HWND hwndParent = GetDlgItem(hwndDlg, IDC_FRAME);
+ LONG_PTR frameExStyle = GetWindowLongPtr(hwndParent, GWL_EXSTYLE);
+ frameExStyle |= WS_EX_CONTROLPARENT;
+ SetWindowLongPtr(hwndParent, GWL_EXSTYLE, frameExStyle);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FRAME), GWLP_WNDPROC, (LONG_PTR)JabberSearchFrameProc);
+
+ int CornerX = 1;
+ int CornerY = 1;
+ RECT rect;
+ GetClientRect(hwndParent, &rect);
+ int width = rect.right - 5 - CornerX;
+
+ int Order = (FieldDat->bHidden) ? -1 : FieldDat->Order;
+
+ HWND hwndLabel = CreateWindowEx(0, L"STATIC", (const wchar_t *)TranslateW(FieldDat->Label), WS_CHILD, CornerX, CornerY + Order * 40, width, 13, hwndParent, nullptr, g_plugin.getInst(), nullptr);
+ HWND hwndVar = CreateWindowEx(0 | WS_EX_CLIENTEDGE, L"EDIT", FieldDat->defValue, WS_CHILD | WS_TABSTOP, CornerX + 5, CornerY + Order * 40 + 14, width, 20, hwndParent, nullptr, g_plugin.getInst(), nullptr);
+ SendMessage(hwndLabel, WM_SETFONT, (WPARAM)hFont, 0);
+ SendMessage(hwndVar, WM_SETFONT, (WPARAM)hFont, 0);
+ if (!FieldDat->bHidden) {
+ ShowWindow(hwndLabel, SW_SHOW);
+ ShowWindow(hwndVar, SW_SHOW);
+ EnableWindow(hwndLabel, !FieldDat->bReadOnly);
+ SendMessage(hwndVar, EM_SETREADONLY, (WPARAM)FieldDat->bReadOnly, 0);
+ }
+
+ // remade list
+ // reallocation
+ JabberSearchData *dat = (JabberSearchData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ if (dat) {
+ dat->pJSInf = (JabberSearchFieldsInfo*)realloc(dat->pJSInf, sizeof(JabberSearchFieldsInfo)*(dat->nJSInfCount + 1));
+ dat->pJSInf[dat->nJSInfCount].hwndCaptionItem = hwndLabel;
+ dat->pJSInf[dat->nJSInfCount].hwndValueItem = hwndVar;
+ dat->pJSInf[dat->nJSInfCount].szFieldCaption = wcsdup(FieldDat->Label);
+ dat->pJSInf[dat->nJSInfCount].szFieldName = wcsdup(FieldDat->Var);
+ dat->nJSInfCount++;
+ }
+ return CornerY + Order * 40 + 14 + 20;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Available search field request result handler (XEP-0055. Examples 2, 7)
+
+void CJabberProto::OnIqResultGetSearchFields(const TiXmlElement *iqNode, CJabberIqInfo*)
+{
+ if (!searchHandleDlg)
+ return;
+
+ const char *type = XmlGetAttr(iqNode, "type");
+ if (type == nullptr)
+ return;
+
+ if (!mir_strcmp(type, "result")) {
+ auto *queryNode = XmlFirstChild(iqNode, "query");
+ auto *xNode = XmlGetChildByTag(queryNode, "x", "xmlns", JABBER_FEAT_DATA_FORMS);
+
+ ShowWindow(searchHandleDlg, SW_HIDE);
+ if (xNode) {
+ // 1. Form
+ PostMessage(searchHandleDlg, WM_USER + 11, (WPARAM)xNode, 0);
+ auto *xcNode = XmlFirstChild(xNode, "instructions");
+ if (xcNode)
+ SetDlgItemTextUtf(searchHandleDlg, IDC_INSTRUCTIONS, xcNode->GetText());
+ }
+ else {
+ int Order = 0;
+ for (auto *chNode : TiXmlEnum(queryNode)) {
+ if (!mir_strcmpi(chNode->Name(), "instructions") && chNode->GetText())
+ SetDlgItemText(searchHandleDlg, IDC_INSTRUCTIONS, TranslateW(Utf2T(chNode->GetText())));
+ else if (chNode->Name()) {
+ Data *MyData = (Data*)malloc(sizeof(Data));
+ memset(MyData, 0, sizeof(Data));
+
+ MyData->Label = mir_utf8decodeW(chNode->Name());
+ MyData->Var = mir_utf8decodeW(chNode->Name());
+ MyData->defValue = mir_utf8decodeW(chNode->GetText());
+ MyData->Order = Order;
+ if (MyData->defValue)
+ MyData->bReadOnly = true;
+ PostMessage(searchHandleDlg, WM_USER + 10, FALSE, (LPARAM)MyData);
+ Order++;
+ }
+ }
+ }
+
+ const char *szFrom = XmlGetAttr(iqNode, "from");
+ if (szFrom)
+ SearchAddToRecent(szFrom, searchHandleDlg);
+ PostMessage(searchHandleDlg, WM_USER + 10, 0, 0);
+ ShowWindow(searchHandleDlg, SW_SHOW);
+ }
+ else if (!mir_strcmp(type, "error")) {
+ const char *code = "";
+ const char *description = "";
+ auto *errorNode = XmlFirstChild(iqNode, "error");
+ if (errorNode) {
+ code = XmlGetAttr(errorNode, "code");
+ description = errorNode->GetText();
+ }
+
+ char buff[255];
+ mir_snprintf(buff, TranslateU("Error %s %s\r\nPlease select other server"), code, description);
+ SetDlgItemTextUtf(searchHandleDlg, IDC_INSTRUCTIONS, buff);
+ }
+ else SetDlgItemText(searchHandleDlg, IDC_INSTRUCTIONS, TranslateT("Error: unknown reply received\r\nPlease select other server"));
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// Return results to search dialog
+// The pmFields is the pointer to map of <field Name, field Label> Not unical but ordered
+// This can help to made result parser routines more simple
+
+static char *nickfields[] = { "nick", "nickname", "fullname", "name", "given", "first", "jid", nullptr };
+
+static int TCharKeyCmp(const char *p1, const char *p2)
+{
+ return mir_strcmpi(p1, p2);
+}
+
+static void SearchReturnResults(CJabberProto *ppro, HANDLE id, LIST<UNIQUE_MAP> &plUsersInfo, UNIQUE_MAP &pmAllFields)
+{
+ LIST<char> ListOfNonEmptyFields(20, TCharKeyCmp);
+ LIST<char> ListOfFields(20);
+
+ // lets fill the ListOfNonEmptyFields but in users order
+ for (auto &pmUserData : plUsersInfo) {
+ int nUserFields = pmUserData->getCount();
+ for (int j = 0; j < nUserFields; j++) {
+ char *var = pmUserData->getKeyName(j);
+ if (var && ListOfNonEmptyFields.getIndex(var) < 0)
+ ListOfNonEmptyFields.insert(var);
+ }
+ }
+
+ // now fill the ListOfFields but order is from pmAllFields
+ int nAllCount = pmAllFields.getCount();
+ for (int i = 0; i < nAllCount; i++) {
+ char *var = pmAllFields.getUnOrderedKeyName(i);
+ if (var && ListOfNonEmptyFields.getIndex(var) < 0)
+ continue;
+ ListOfFields.insert(var);
+ }
+
+ // now lets transfer field names
+ int nFieldCount = ListOfFields.getCount();
+
+ CUSTOMSEARCHRESULTS Results = { 0 };
+ Results.nSize = sizeof(Results);
+ Results.pszFields = (wchar_t**)mir_alloc(sizeof(wchar_t*)*nFieldCount);
+ Results.nFieldCount = nFieldCount;
+
+ // Sending Columns Titles
+ for (int i = 0; i < nFieldCount; i++) {
+ char *var = ListOfFields[i];
+ if (var)
+ Results.pszFields[i] = mir_utf8decodeW(pmAllFields[var]);
+ }
+
+ Results.psr.cbSize = 0; // sending column names
+ ppro->ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SEARCHRESULT, id, (LPARAM)&Results);
+ for (int i = 0; i < nFieldCount; i++)
+ replaceStrW(Results.pszFields[i], nullptr);
+
+ // Sending Users Data
+ Results.psr.cbSize = sizeof(Results.psr);
+
+ for (auto &pmUserData : plUsersInfo) {
+ for (int j = 0; j < nFieldCount; j++) {
+ char *var = ListOfFields[j];
+ char *value = pmUserData->operator [](var);
+ Results.pszFields[j] = value ? mir_utf8decodeW(value) : mir_wstrdup(L" ");
+ if (!mir_strcmpi(var, "jid") && value)
+ Results.psr.id.w = Results.pszFields[j];
+ }
+
+ const char *nick = nullptr;
+ for (int k = 0; k < _countof(nickfields) && !nick; k++)
+ nick = pmUserData->operator [](nickfields[k]);
+
+ if (nick) {
+ Utf2T wszNick(nick);
+ wchar_t buff[200];
+ if (mir_wstrcmpi(wszNick, Results.psr.id.w))
+ mir_snwprintf(buff, L"%s (%s)", wszNick.get(), Results.psr.id.w);
+ else
+ wcsncpy_s(buff, wszNick, _TRUNCATE);
+
+ Results.psr.nick.w = buff;
+ }
+ else Results.psr.nick.w = L"";
+ Results.psr.flags = PSR_UNICODE;
+
+ ppro->ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SEARCHRESULT, id, (LPARAM)&Results);
+ for (int i = 0; i < nFieldCount; i++)
+ replaceStrW(Results.pszFields[i], nullptr);
+ }
+
+ mir_free(Results.pszFields);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Search field request result handler (XEP-0055. Examples 3, 8)
+
+void CJabberProto::OnIqResultAdvancedSearch(const TiXmlElement *iqNode, CJabberIqInfo*)
+{
+ const char *type;
+ int id;
+
+ UNIQUE_MAP mColumnsNames(10);
+ LIST<UNIQUE_MAP> SearchResults(2);
+
+ if (((id = JabberGetPacketID(iqNode)) == -1) || ((type = XmlGetAttr(iqNode, "type")) == nullptr)) {
+ ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)id);
+ return;
+ }
+
+ if (!mir_strcmp(type, "result")) {
+ auto *queryNode = XmlFirstChild(iqNode, "query");
+ auto *xNode = XmlGetChildByTag(queryNode, "x", "xmlns", JABBER_FEAT_DATA_FORMS);
+ if (xNode) {
+ // 1. Form search results info
+ for (auto *fieldNode : TiXmlFilter(XmlFirstChild(xNode, "reported"), "field")) {
+ auto *var = XmlGetAttr(fieldNode, "var");
+ if (var) {
+ auto *label = XmlGetAttr(fieldNode, "label");
+ mColumnsNames.insert(var, (label != nullptr) ? label : var);
+ }
+ }
+
+ for (auto *itemNode : TiXmlFilter(xNode, "item")) {
+ UNIQUE_MAP *pUserColumn = new UNIQUE_MAP(10);
+ for (auto *fieldNode : TiXmlFilter(itemNode, "field")) {
+ if (auto *var = XmlGetAttr(fieldNode, "var")) {
+ if (auto *textNode = XmlFirstChild(fieldNode, "value")) {
+ if (!mColumnsNames[var])
+ mColumnsNames.insert(var, var);
+ pUserColumn->insert(var, textNode->GetText());
+ }
+ }
+ }
+
+ SearchResults.insert(pUserColumn);
+ }
+ }
+ else {
+ // 2. Field list search results info
+ for (auto *itemNode : TiXmlFilter(queryNode, "item")) {
+ UNIQUE_MAP *pUserColumn = new UNIQUE_MAP(10);
+
+ auto *jid = XmlGetAttr(itemNode, "jid");
+ char *keyReturned;
+ mColumnsNames.insertCopyKey("jid", "jid", &keyReturned);
+ mColumnsNames.insert("jid", keyReturned);
+ pUserColumn->insertCopyKey("jid", jid, nullptr);
+
+ for (auto *child : TiXmlEnum(itemNode)) {
+ const char *szColumnName = child->Name();
+ if (szColumnName) {
+ const char *pszChild = child->GetText();
+ if (pszChild && *pszChild) {
+ mColumnsNames.insertCopyKey(szColumnName, "", &keyReturned);
+ mColumnsNames.insert(szColumnName, keyReturned);
+ pUserColumn->insertCopyKey(szColumnName, pszChild, nullptr);
+ }
+ }
+ }
+
+ SearchResults.insert(pUserColumn);
+ }
+ }
+ }
+ else if (!mir_strcmp(type, "error")) {
+ const char *code = "";
+ const char *description = "";
+ auto *errorNode = XmlFirstChild(iqNode, "error");
+ if (errorNode) {
+ code = XmlGetAttr(errorNode, "code");
+ description = errorNode->GetText();
+ }
+
+ ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)id);
+
+ char buff[255];
+ mir_snprintf(buff, TranslateU("Error %s %s\r\nTry to specify more detailed"), code, description);
+ if (searchHandleDlg)
+ SetDlgItemTextUtf(searchHandleDlg, IDC_INSTRUCTIONS, buff);
+ else
+ MessageBox(nullptr, Utf2T(buff), TranslateT("Search error"), MB_OK | MB_ICONSTOP);
+ return;
+ }
+
+ SearchReturnResults(this, (HANDLE)id, SearchResults, mColumnsNames);
+
+ for (auto &it : SearchResults)
+ delete ((UNIQUE_MAP*)it);
+
+ //send success to finish searching
+ ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)id);
+}
+
+static BOOL CALLBACK DeleteChildWindowsProc(HWND hwnd, LPARAM)
+{
+ DestroyWindow(hwnd);
+ return TRUE;
+}
+
+static void JabberSearchFreeData(HWND hwndDlg, JabberSearchData * dat)
+{
+ if (!dat->fSearchRequestIsXForm && dat->nJSInfCount && dat->pJSInf) {
+ for (int i = 0; i < dat->nJSInfCount; i++) {
+ if (dat->pJSInf[i].hwndValueItem)
+ DestroyWindow(dat->pJSInf[i].hwndValueItem);
+ if (dat->pJSInf[i].hwndCaptionItem)
+ DestroyWindow(dat->pJSInf[i].hwndCaptionItem);
+ if (dat->pJSInf[i].szFieldCaption)
+ free(dat->pJSInf[i].szFieldCaption);
+ if (dat->pJSInf[i].szFieldName)
+ free(dat->pJSInf[i].szFieldName);
+ }
+ free(dat->pJSInf);
+ dat->pJSInf = nullptr;
+ }
+ else EnumChildWindows(GetDlgItem(hwndDlg, IDC_FRAME), DeleteChildWindowsProc, 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_FRAME, WM_SETFONT, (WPARAM)SendMessage(hwndDlg, WM_GETFONT, 0, 0), 0);
+ dat->nJSInfCount = 0;
+ ShowWindow(GetDlgItem(hwndDlg, IDC_VSCROLL), SW_HIDE);
+ SetDlgItemText(hwndDlg, IDC_INSTRUCTIONS, TranslateT("Select/type search service URL above and press <Go>"));
+}
+
+static void JabberSearchRefreshFrameScroll(HWND hwndDlg, JabberSearchData *dat)
+{
+ HWND hFrame = GetDlgItem(hwndDlg, IDC_FRAME);
+ HWND hwndScroll = GetDlgItem(hwndDlg, IDC_VSCROLL);
+ RECT rc;
+ GetClientRect(hFrame, &rc);
+ GetClientRect(hFrame, &dat->frameRect);
+ dat->frameHeight = rc.bottom - rc.top;
+ if (dat->frameHeight < dat->CurrentHeight) {
+ ShowWindow(hwndScroll, SW_SHOW);
+ EnableWindow(hwndScroll, TRUE);
+ }
+ else ShowWindow(hwndScroll, SW_HIDE);
+
+ SetScrollRange(hwndScroll, SB_CTL, 0, dat->CurrentHeight - dat->frameHeight, FALSE);
+}
+
+int CJabberProto::SearchRenewFields(HWND hwndDlg, JabberSearchData *dat)
+{
+ wchar_t szServerName[100];
+ EnableWindow(GetDlgItem(hwndDlg, IDC_GO), FALSE);
+ GetDlgItemText(hwndDlg, IDC_SERVER, szServerName, _countof(szServerName));
+ dat->CurrentHeight = 0;
+ dat->curPos = 0;
+ SetScrollPos(GetDlgItem(hwndDlg, IDC_VSCROLL), SB_CTL, 0, FALSE);
+
+ JabberSearchFreeData(hwndDlg, dat);
+ JabberSearchRefreshFrameScroll(hwndDlg, dat);
+
+ SetDlgItemText(hwndDlg, IDC_INSTRUCTIONS, m_bJabberOnline ? TranslateT("Please wait...\r\nConnecting search server...") : TranslateT("You have to be connected to server"));
+
+ if (!m_bJabberOnline)
+ return 0;
+
+ searchHandleDlg = hwndDlg;
+
+ CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultGetSearchFields, JABBER_IQ_TYPE_GET, T2Utf(szServerName));
+ m_ThreadInfo->send(XmlNodeIq(pInfo) << XQUERY(JABBER_FEAT_JUD));
+ return pInfo->GetIqId();
+}
+
+static void JabberSearchAddUrlToRecentCombo(HWND hwndDlg, const wchar_t *szAddr)
+{
+ int lResult = SendDlgItemMessage(hwndDlg, IDC_SERVER, (UINT)CB_FINDSTRING, 0, (LPARAM)szAddr);
+ if (lResult == -1)
+ SendDlgItemMessage(hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, (LPARAM)szAddr);
+}
+
+void CJabberProto::SearchDeleteFromRecent(const char *szAddr, bool deleteLastFromDB)
+{
+ // search in recent
+ for (int i = 0; i < 10; i++) {
+ char key[30];
+ mir_snprintf(key, "RecentlySearched_%d", i);
+ ptrA szValue(getUStringA(key));
+ if (szValue == nullptr || mir_strcmpi(szAddr, szValue))
+ continue;
+
+ for (int j = i; j < 10; j++) {
+ mir_snprintf(key, "RecentlySearched_%d", j + 1);
+ szValue = getUStringA(key);
+ if (szValue != nullptr) {
+ mir_snprintf(key, "RecentlySearched_%d", j);
+ setUString(0, key, szValue);
+ }
+ else {
+ if (deleteLastFromDB) {
+ mir_snprintf(key, "RecentlySearched_%d", j);
+ delSetting(0, key);
+ }
+ break;
+ }
+ }
+ break;
+ }
+}
+
+void CJabberProto::SearchAddToRecent(const char *szAddr, HWND hwndDialog)
+{
+ char key[30];
+ SearchDeleteFromRecent(szAddr, true);
+
+ for (int j = 9; j > 0; j--) {
+ mir_snprintf(key, "RecentlySearched_%d", j - 1);
+ ptrW szValue(getWStringA(key));
+ if (szValue != nullptr) {
+ mir_snprintf(key, "RecentlySearched_%d", j);
+ setWString(0, key, szValue);
+ }
+ }
+
+ mir_snprintf(key, "RecentlySearched_%d", 0);
+ setUString(key, szAddr);
+ if (hwndDialog)
+ JabberSearchAddUrlToRecentCombo(hwndDialog, Utf2T(szAddr));
+}
+
+static INT_PTR CALLBACK JabberSearchAdvancedDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ JabberSearchData *dat = (JabberSearchData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ {
+ dat = new JabberSearchData();
+ dat->ppro = (CJabberProto *)lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
+
+ /* Server Combo box */
+ ptrA jud(dat->ppro->getStringA("Jud"));
+ if (jud != nullptr) {
+ SetDlgItemTextA(hwndDlg, IDC_SERVER, jud);
+ SendDlgItemMessageA(hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, jud);
+ }
+
+ //TO DO: Add Transports here
+ for (auto &it : dat->ppro->m_lstTransports)
+ if (it != nullptr)
+ JabberSearchAddUrlToRecentCombo(hwndDlg, Utf2T(it));
+
+ for (int i = 0; i < 10; i++) {
+ char key[30];
+ mir_snprintf(key, "RecentlySearched_%d", i);
+ ptrW szValue(dat->ppro->getWStringA(key));
+ if (szValue != nullptr)
+ JabberSearchAddUrlToRecentCombo(hwndDlg, szValue);
+ }
+
+ //TO DO: Add 4 recently used
+ dat->lastRequestIq = dat->ppro->SearchRenewFields(hwndDlg, dat);
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_SERVER) {
+ switch (HIWORD(wParam)) {
+ case CBN_SETFOCUS:
+ PostMessage(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(0, EN_SETFOCUS), (LPARAM)hwndDlg);
+ return TRUE;
+
+ case CBN_EDITCHANGE:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_GO), TRUE);
+ return TRUE;
+
+ case CBN_EDITUPDATE:
+ JabberSearchFreeData(hwndDlg, dat);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_GO), TRUE);
+ return TRUE;
+
+ case CBN_SELENDOK:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_GO), TRUE);
+ PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_GO, BN_CLICKED), 0);
+ return TRUE;
+ }
+ }
+ else if (LOWORD(wParam) == IDC_GO && HIWORD(wParam) == BN_CLICKED) {
+ dat->ppro->SearchRenewFields(hwndDlg, dat);
+ return TRUE;
+ }
+ break;
+
+ case WM_SIZE:
+ {
+ //Resize IDC_FRAME to take full size
+ RECT rcForm;
+ GetWindowRect(hwndDlg, &rcForm);
+ RECT rcFrame;
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_FRAME), &rcFrame);
+ rcFrame.bottom = rcForm.bottom;
+ SetWindowPos(GetDlgItem(hwndDlg, IDC_FRAME), nullptr, 0, 0, rcFrame.right - rcFrame.left, rcFrame.bottom - rcFrame.top, SWP_NOZORDER | SWP_NOMOVE);
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_VSCROLL), &rcForm);
+ SetWindowPos(GetDlgItem(hwndDlg, IDC_VSCROLL), nullptr, 0, 0, rcForm.right - rcForm.left, rcFrame.bottom - rcFrame.top, SWP_NOZORDER | SWP_NOMOVE);
+ JabberSearchRefreshFrameScroll(hwndDlg, dat);
+ }
+ return TRUE;
+
+ case WM_USER + 11:
+ {
+ dat->fSearchRequestIsXForm = TRUE;
+ if (dat->xNode) {
+ dat->doc.DeleteNode(dat->xNode);
+ dat->xNode = nullptr;
+ }
+ TiXmlElement *pNode = (TiXmlElement *)wParam;
+ if (pNode) {
+ dat->xNode = pNode->DeepClone(&dat->doc)->ToElement();
+ JabberFormCreateUI(GetDlgItem(hwndDlg, IDC_FRAME), dat->xNode, &dat->CurrentHeight, TRUE);
+ }
+ ShowWindow(GetDlgItem(hwndDlg, IDC_FRAME), SW_SHOW);
+ dat->nJSInfCount = 1;
+ }
+ return TRUE;
+
+ case WM_USER + 10:
+ {
+ Data *MyDat = (Data *)lParam;
+ if (MyDat) {
+ dat->fSearchRequestIsXForm = (BOOL)wParam;
+ dat->CurrentHeight = JabberSearchAddField(hwndDlg, MyDat);
+ mir_free(MyDat->Label);
+ mir_free(MyDat->Var);
+ mir_free(MyDat->defValue);
+ free(MyDat);
+ }
+ else {
+ JabberSearchRefreshFrameScroll(hwndDlg, dat);
+ ScrollWindow(GetDlgItem(hwndDlg, IDC_FRAME), 0, dat->curPos - 0, nullptr, &(dat->frameRect));
+ SetScrollPos(GetDlgItem(hwndDlg, IDC_VSCROLL), SB_CTL, 0, FALSE);
+ dat->curPos = 0;
+ }
+ }
+ return TRUE;
+
+ case WM_MOUSEWHEEL:
+ {
+ short zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
+ if (zDelta) {
+ int nScrollLines = 0;
+ SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, (void *)&nScrollLines, 0);
+ for (int i = 0; i < (nScrollLines + 1) / 2; i++)
+ SendMessage(hwndDlg, WM_VSCROLL, (zDelta < 0) ? SB_LINEDOWN : SB_LINEUP, 0);
+ }
+ }
+ return TRUE;
+
+ case WM_VSCROLL:
+ {
+ int pos;
+ if (dat != nullptr) {
+ pos = dat->curPos;
+ switch (LOWORD(wParam)) {
+ case SB_LINEDOWN:
+ pos += 10;
+ break;
+ case SB_LINEUP:
+ pos -= 10;
+ break;
+ case SB_PAGEDOWN:
+ pos += (dat->CurrentHeight - 10);
+ break;
+ case SB_PAGEUP:
+ pos -= (dat->CurrentHeight - 10);
+ break;
+ case SB_THUMBTRACK:
+ pos = HIWORD(wParam);
+ break;
+ }
+ if (pos > (dat->CurrentHeight - dat->frameHeight))
+ pos = dat->CurrentHeight - dat->frameHeight;
+ if (pos < 0)
+ pos = 0;
+ if (dat->curPos != pos) {
+ ScrollWindow(GetDlgItem(hwndDlg, IDC_FRAME), 0, dat->curPos - pos, nullptr, &(dat->frameRect));
+ SetScrollPos(GetDlgItem(hwndDlg, IDC_VSCROLL), SB_CTL, pos, TRUE);
+ RECT Invalid = dat->frameRect;
+ if (dat->curPos - pos > 0)
+ Invalid.bottom = Invalid.top + (dat->curPos - pos);
+ else
+ Invalid.top = Invalid.bottom + (dat->curPos - pos);
+
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_FRAME), nullptr, nullptr, RDW_UPDATENOW | RDW_ALLCHILDREN);
+ dat->curPos = pos;
+ }
+ }
+ }
+ return TRUE;
+
+ case WM_DESTROY:
+ JabberSearchFreeData(hwndDlg, dat);
+ JabberFormDestroyUI(GetDlgItem(hwndDlg, IDC_FRAME));
+ delete dat;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+HWND CJabberProto::CreateExtendedSearchUI(HWND parent)
+{
+ if (parent && g_plugin.getInst()) {
+ ptrW szServer(getWStringA("LoginServer"));
+ if (szServer == nullptr || mir_wstrcmpi(szServer, L"S.ms"))
+ return CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_SEARCHUSER), parent, JabberSearchAdvancedDlgProc, (LPARAM)this);
+ }
+
+ return nullptr; // Failure
+}
+
+//////////////////////////////////////////////////////////////////////////
+// The function formats request to server
+
+HWND CJabberProto::SearchAdvanced(HWND hwndDlg)
+{
+ if (!m_bJabberOnline || !hwndDlg)
+ return nullptr; //error
+
+ JabberSearchData *dat = (JabberSearchData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ if (!dat)
+ return nullptr; //error
+
+ // check if server connected (at least one field exists)
+ if (dat->nJSInfCount == 0)
+ return nullptr;
+
+ // formating request
+ bool fRequestNotEmpty = false;
+
+ // get server name
+ wchar_t szServerName[100];
+ GetDlgItemText(hwndDlg, IDC_SERVER, szServerName, _countof(szServerName));
+
+ // formating query
+ CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultAdvancedSearch, JABBER_IQ_TYPE_SET, T2Utf(szServerName));
+ XmlNodeIq iq(pInfo);
+ TiXmlElement *query = iq << XQUERY(JABBER_FEAT_JUD);
+
+ if (m_tszSelectedLang)
+ iq << XATTR("xml:lang", m_tszSelectedLang); // i'm sure :)
+
+ // next can be 2 cases:
+ // Forms: XEP-0055 Example 7
+ if (dat->fSearchRequestIsXForm) {
+ fRequestNotEmpty = true;
+ JabberFormGetData(GetDlgItem(hwndDlg, IDC_FRAME), query, dat->xNode);
+ }
+ else { //and Simple fields: XEP-0055 Example 3
+ for (int i = 0; i < dat->nJSInfCount; i++) {
+ wchar_t szFieldValue[100];
+ GetWindowText(dat->pJSInf[i].hwndValueItem, szFieldValue, _countof(szFieldValue));
+ if (szFieldValue[0] != 0) {
+ XmlAddChildA(query, T2Utf(dat->pJSInf[i].szFieldName).get(), T2Utf(szFieldValue).get());
+ fRequestNotEmpty = true;
+ }
+ }
+ }
+
+ if (fRequestNotEmpty) {
+ m_ThreadInfo->send(iq);
+ return (HWND)pInfo->GetIqId();
+ }
+ return nullptr;
+}
diff --git a/protocols/JabberG/src/jabber_search.h b/protocols/JabberG/src/jabber_search.h
index 4916afb29a..3bfaa2df8a 100644
--- a/protocols/JabberG/src/jabber_search.h
+++ b/protocols/JabberG/src/jabber_search.h
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Artem Shpynov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
Module implements a search according to XEP-0055: Jabber Search
http://www.xmpp.org/extensions/xep-0055.html
diff --git a/protocols/JabberG/src/jabber_secur.cpp b/protocols/JabberG/src/jabber_secur.cpp
index a1cf3faccc..853016823d 100644
--- a/protocols/JabberG/src/jabber_secur.cpp
+++ b/protocols/JabberG/src/jabber_secur.cpp
@@ -4,7 +4,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_secur.h b/protocols/JabberG/src/jabber_secur.h
index 133d55e840..90ad39bd60 100644
--- a/protocols/JabberG/src/jabber_secur.h
+++ b/protocols/JabberG/src/jabber_secur.h
@@ -4,7 +4,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_send_manager.cpp b/protocols/JabberG/src/jabber_send_manager.cpp
index c70d4017af..67031c0567 100644
--- a/protocols/JabberG/src/jabber_send_manager.cpp
+++ b/protocols/JabberG/src/jabber_send_manager.cpp
@@ -6,7 +6,7 @@ Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-08 George Hazan
Copyright (c) 2007 Maxim Mluhov
Copyright (c) 2008-09 Dmitriy Chervov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_send_manager.h b/protocols/JabberG/src/jabber_send_manager.h
index d223782694..9b98db0458 100644
--- a/protocols/JabberG/src/jabber_send_manager.h
+++ b/protocols/JabberG/src/jabber_send_manager.h
@@ -6,7 +6,7 @@ Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-08 George Hazan
Copyright (c) 2007 Maxim Mluhov
Copyright (c) 2008-09 Dmitriy Chervov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_strm_mgmt.cpp b/protocols/JabberG/src/jabber_strm_mgmt.cpp
index e0f95eb2a8..a081570cfe 100644
--- a/protocols/JabberG/src/jabber_strm_mgmt.cpp
+++ b/protocols/JabberG/src/jabber_strm_mgmt.cpp
@@ -2,7 +2,7 @@
Jabber Protocol Plugin for Miranda NG
-Copyright (c) 2018-22 Miranda NG team
+Copyright (c) 2018-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_strm_mgmt.h b/protocols/JabberG/src/jabber_strm_mgmt.h
index 412127d1d2..158c72fefb 100644
--- a/protocols/JabberG/src/jabber_strm_mgmt.h
+++ b/protocols/JabberG/src/jabber_strm_mgmt.h
@@ -2,7 +2,7 @@
Jabber Protocol Plugin for Miranda NG
-Copyright (c) 2018-22 Miranda NG team
+Copyright (c) 2018-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_svc.cpp b/protocols/JabberG/src/jabber_svc.cpp
index 63fbd74e8b..5252c0865f 100644
--- a/protocols/JabberG/src/jabber_svc.cpp
+++ b/protocols/JabberG/src/jabber_svc.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_thread.cpp b/protocols/JabberG/src/jabber_thread.cpp
index 212c6bdd6a..0ad67e79dd 100644
--- a/protocols/JabberG/src/jabber_thread.cpp
+++ b/protocols/JabberG/src/jabber_thread.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_treelist.cpp b/protocols/JabberG/src/jabber_treelist.cpp
index 21fcb1fbc5..35467cbd1c 100644
--- a/protocols/JabberG/src/jabber_treelist.cpp
+++ b/protocols/JabberG/src/jabber_treelist.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Victor Pavlychko
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_userinfo.cpp b/protocols/JabberG/src/jabber_userinfo.cpp
index f164252fbd..0f9271481a 100644
--- a/protocols/JabberG/src/jabber_userinfo.cpp
+++ b/protocols/JabberG/src/jabber_userinfo.cpp
@@ -1,912 +1,912 @@
-/*
-
-Jabber Protocol Plugin for Miranda NG
-
-Copyright (c) 2002-04 Santithorn Bunchua
-Copyright (c) 2005-12 George Hazan
-Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
-
-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; either version 2
-of the License, or (at your option) any later version.
-
-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, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-*/
-
-#include "stdafx.h"
-
-#include <fcntl.h>
-#include <io.h>
-#include <sys/stat.h>
-
-#include "jabber_list.h"
-
-static MWindowList hUserInfoList = nullptr;
-
-class JabberBaseUserInfoDlg : public CUserInfoPageDlg
-{
- INT_PTR DoRefresh(UINT, WPARAM, LPARAM)
- {
- OnRefresh();
- return 0;
- }
-
-protected:
- UI_MESSAGE_MAP(JabberBaseUserInfoDlg, CUserInfoPageDlg);
- UI_MESSAGE(WM_PROTO_REFRESH, DoRefresh);
- UI_MESSAGE(WM_JABBER_REFRESH_VCARD, DoRefresh);
- UI_MESSAGE_MAP_END();
-
- CJabberProto *ppro;
-
- JabberBaseUserInfoDlg(CJabberProto *_ppro, int dlgId) :
- CUserInfoPageDlg(g_plugin, dlgId),
- ppro(_ppro)
- {}
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// JabberUserInfoDlgProc - main user info dialog
-
-enum
-{
- INFOLINE_DELETE = 0x80000000,
- INFOLINE_MASK = 0x7fffffff,
- INFOLINE_BAD_ID = 0x7fffffff,
-
- INFOLINE_NAME = 1,
- INFOLINE_MOOD,
- INFOLINE_ACTIVITY,
- INFOLINE_TUNE,
- INFOLINE_OFFLINE,
- INFOLINE_MESSAGE,
- INFOLINE_SOFTWARE,
- INFOLINE_VERSION,
- INFOLINE_SYSTEM,
- INFOLINE_PRIORITY,
- INFOLINE_IDLE,
- INFOLINE_CAPS,
- INFOLINE_SOFTWARE_INFORMATION,
- INFOLINE_SUBSCRIPTION,
- INFOLINE_LOGOFF,
- INFOLINE_LOGOFF_MSG,
- INFOLINE_LASTACTIVE,
-};
-
-__forceinline uint32_t sttInfoLineId(uint32_t res, uint32_t type, uint32_t line = 0)
-{
- return
- (type << 24) & 0x7f000000 |
- (res << 12) & 0x00fff000 |
- (line) & 0x00000fff;
-}
-
-class JabberUserInfoDlg : public JabberBaseUserInfoDlg
-{
- JABBER_LIST_ITEM *item = nullptr;
- int resourcesCount = -1;
-
- CCtrlTreeView m_tree;
-
- UI_MESSAGE_MAP(JabberUserInfoDlg, JabberBaseUserInfoDlg);
- UI_MESSAGE(WM_PROTO_CHECK_ONLINE, OnCheckOnline);
- UI_MESSAGE_MAP_END();
-
- INT_PTR OnCheckOnline(UINT, WPARAM, LPARAM)
- {
- if (!ppro->m_bJabberOnline)
- item = nullptr;
- else
- OnRefresh();
- return 0;
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////
- // User information block
-
- void CleanupInfo(int stage)
- {
- HTREEITEM hItem = m_tree.GetRoot();
- while (hItem) {
- TVITEMEX tvi = { 0 };
- tvi.mask = TVIF_HANDLE | TVIF_PARAM;
- tvi.hItem = hItem;
- m_tree.GetItem(&tvi);
-
- switch (stage) {
- case 0:
- tvi.lParam |= INFOLINE_DELETE;
- m_tree.SetItem(&tvi);
- break;
-
- case 1:
- if (tvi.lParam & INFOLINE_DELETE) {
- hItem = m_tree.GetNextSibling(hItem);
- m_tree.DeleteItem(tvi.hItem);
- continue;
- }
- break;
- }
-
- HTREEITEM hItemTmp = nullptr;
- if (hItemTmp = m_tree.GetChild(hItem))
- hItem = hItemTmp;
- else if (hItemTmp = m_tree.GetNextSibling(hItem))
- hItem = hItemTmp;
- else {
- while (true) {
- if (!(hItem = m_tree.GetParent(hItem))) break;
- if (hItemTmp = m_tree.GetNextSibling(hItem)) {
- hItem = hItemTmp;
- break;
- }
- }
- }
- }
- }
-
- HTREEITEM FindInfoLine(HTREEITEM htiRoot, LPARAM id = INFOLINE_BAD_ID)
- {
- if (id == INFOLINE_BAD_ID) return nullptr;
- for (HTREEITEM hti = m_tree.GetChild(htiRoot); hti; hti = m_tree.GetNextSibling(hti)) {
- TVITEMEX tvi = { 0 };
- tvi.mask = TVIF_HANDLE | TVIF_PARAM;
- tvi.hItem = hti;
- m_tree.GetItem(&tvi);
- if ((tvi.lParam&INFOLINE_MASK) == (id&INFOLINE_MASK))
- return hti;
- }
- return nullptr;
- }
-
- HTREEITEM FillInfoLine(HTREEITEM htiRoot, HICON hIcon, const wchar_t *title, const char *value, LPARAM id = INFOLINE_BAD_ID, bool expand = false)
- {
- HTREEITEM hti = FindInfoLine(htiRoot, id);
-
- Utf2T wszValue(value);
- const wchar_t *pwszValue = (value == nullptr) ? TranslateT("<not specified>") : wszValue;
- wchar_t buf[256];
- if (title)
- mir_snwprintf(buf, L"%s: %s", title, pwszValue);
- else
- mir_wstrncpy(buf, pwszValue, _countof(buf));
-
- TVINSERTSTRUCT tvis = {};
- tvis.hParent = htiRoot;
- tvis.hInsertAfter = TVI_LAST;
- tvis.itemex.mask = TVIF_TEXT | TVIF_PARAM;
- tvis.itemex.pszText = buf;
- tvis.itemex.lParam = id;
-
- if (hIcon) {
- HIMAGELIST himl = m_tree.GetImageList(TVSIL_NORMAL);
- tvis.itemex.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE;
- tvis.itemex.iImage =
- tvis.itemex.iSelectedImage = ImageList_AddIcon(himl, hIcon);
- IcoLib_ReleaseIcon(hIcon);
- }
-
- if (hti) {
- tvis.itemex.mask |= TVIF_HANDLE;
- tvis.itemex.hItem = hti;
- m_tree.SetItem(&tvis.itemex);
- }
- else {
- tvis.itemex.mask |= TVIF_STATE;
- tvis.itemex.stateMask = TVIS_EXPANDED;
- tvis.itemex.state = expand ? TVIS_EXPANDED : 0;
- hti = m_tree.InsertItem(&tvis);
- }
-
- return hti;
- }
-
- void FillAdvStatusInfo(HTREEITEM htiRoot, uint32_t dwInfoLine, MCONTACT hContact, wchar_t *szTitle, char *pszSlot)
- {
- ptrA szAdvStatusIcon(ppro->ReadAdvStatusA(hContact, pszSlot, ADVSTATUS_VAL_ICON));
- ptrW szAdvStatusTitle(ppro->ReadAdvStatusT(hContact, pszSlot, ADVSTATUS_VAL_TITLE));
- ptrW szAdvStatusText(ppro->ReadAdvStatusT(hContact, pszSlot, ADVSTATUS_VAL_TEXT));
-
- if (szAdvStatusIcon && szAdvStatusTitle && *szAdvStatusTitle) {
- wchar_t szText[2048];
- if (szAdvStatusText && *szAdvStatusText)
- mir_snwprintf(szText, L"%s (%s)", TranslateW(szAdvStatusTitle), szAdvStatusText.get());
- else
- wcsncpy_s(szText, TranslateW(szAdvStatusTitle), _TRUNCATE);
- FillInfoLine(htiRoot, IcoLib_GetIcon(szAdvStatusIcon), szTitle, T2Utf(szText), dwInfoLine);
- }
- }
-
- void FillResourceInfo(HTREEITEM htiRoot, int resource)
- {
- HTREEITEM htiResource = htiRoot;
- pResourceStatus r = resource ? item->arResources[resource - 1] : item->getTemp();
-
- if (r->m_szResourceName && *r->m_szResourceName)
- htiResource = FillInfoLine(htiRoot, Skin_LoadProtoIcon(ppro->m_szModuleName, r->m_iStatus),
- TranslateT("Resource"), r->m_szResourceName, sttInfoLineId(resource, INFOLINE_NAME), true);
-
- // StatusMsg
- FillInfoLine(htiResource, nullptr /*Skin_LoadIcon(SKINICON_EVENT_MESSAGE)*/,
- TranslateT("Message"), r->m_szStatusMessage,
- sttInfoLineId(resource, INFOLINE_MESSAGE));
-
- // Software
- if (CJabberClientPartialCaps *pCaps = r->m_pCaps) {
- HICON hIcon = nullptr;
-
- if (ServiceExists(MS_FP_GETCLIENTICONT)) {
- if (pCaps->GetSoft()) {
- wchar_t buf[256];
- mir_snwprintf(buf, L"%s %s", pCaps->GetSoft(), pCaps->GetSoftVer());
- hIcon = Finger_GetClientIcon(buf, 0);
- }
- }
-
- FillInfoLine(htiResource, hIcon, TranslateT("Software"), pCaps->GetSoft(), sttInfoLineId(resource, INFOLINE_SOFTWARE));
-
- // Version
- FillInfoLine(htiResource, nullptr, TranslateT("Version"), pCaps->GetSoftMir() ? pCaps->GetSoftMir() : pCaps->GetSoftVer(), sttInfoLineId(resource, INFOLINE_VERSION));
-
- // System
- FillInfoLine(htiResource, nullptr, TranslateT("System"), pCaps->GetOsVer() ? pCaps->GetOsVer() : pCaps->GetOs(), sttInfoLineId(resource, INFOLINE_SYSTEM));
-
- if (hIcon)
- DestroyIcon(hIcon);
- }
-
- // Resource priority
- char buf[256];
- itoa(r->m_iPriority, buf, 10);
- FillInfoLine(htiResource, nullptr, TranslateT("Resource priority"), buf, sttInfoLineId(resource, INFOLINE_PRIORITY));
-
- // Idle
- if (r->m_dwIdleStartTime != -1) {
- if (r->m_dwIdleStartTime != 0) {
- mir_strncpy(buf, ctime(&r->m_dwIdleStartTime), _countof(buf));
- size_t len = mir_strlen(buf);
- if (len > 0)
- buf[len - 1] = 0;
- }
- else mir_strncpy(buf, TranslateU("<currently online>"), _countof(buf));
-
- FillInfoLine(htiResource, nullptr, TranslateT("Last activity"), buf, sttInfoLineId(resource, INFOLINE_IDLE));
- }
-
- // caps
- JabberCapsBits jcb = ppro->GetResourceCapabilities(MakeJid(item->jid, r->m_szResourceName), r);
- if (!(jcb & JABBER_RESOURCE_CAPS_ERROR)) {
- HTREEITEM htiCaps = FillInfoLine(htiResource, IcoLib_GetIconByHandle(ppro->m_hProtoIcon), nullptr, TranslateU("Client capabilities"), sttInfoLineId(resource, INFOLINE_CAPS));
- int i;
- for (i = 0; i < g_cJabberFeatCapPairs; i++)
- if (jcb & g_JabberFeatCapPairs[i].jcbCap) {
- char szDescription[1024];
- if (g_JabberFeatCapPairs[i].tszDescription)
- mir_snprintf(szDescription, "%s (%s)", TranslateU(g_JabberFeatCapPairs[i].tszDescription), g_JabberFeatCapPairs[i].szFeature);
- else
- strncpy_s(szDescription, g_JabberFeatCapPairs[i].szFeature, _TRUNCATE);
- FillInfoLine(htiCaps, nullptr, nullptr, szDescription, sttInfoLineId(resource, INFOLINE_CAPS, i));
- }
-
- for (auto &it : ppro->m_lstJabberFeatCapPairsDynamic) {
- if (jcb & it->jcbCap) {
- char szDescription[1024];
- if (it->szDescription)
- mir_snprintf(szDescription, "%s (%s)", TranslateU(it->szDescription), it->szFeature);
- else
- strncpy_s(szDescription, it->szFeature, _TRUNCATE);
- FillInfoLine(htiCaps, nullptr, nullptr, szDescription, sttInfoLineId(resource, INFOLINE_CAPS, i++));
- }
- }
- }
-
- // Software info
- HTREEITEM htiSoftwareInfo = FillInfoLine(htiResource, IcoLib_GetIconByHandle(ppro->m_hProtoIcon), nullptr, TranslateU("Software information"), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION));
- int nLineId = 0;
- if (CJabberClientPartialCaps *pCaps = r->m_pCaps) {
- if (pCaps->GetOs())
- FillInfoLine(htiSoftwareInfo, nullptr, TranslateT("Operating system"), pCaps->GetOs(), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++));
- if (pCaps->GetOsVer())
- FillInfoLine(htiSoftwareInfo, nullptr, TranslateT("Operating system version"), pCaps->GetOsVer(), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++));
- if (pCaps->GetSoft())
- FillInfoLine(htiSoftwareInfo, nullptr, TranslateT("Software"), pCaps->GetSoft(), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++));
- if (pCaps->GetSoftVer())
- FillInfoLine(htiSoftwareInfo, nullptr, TranslateT("Software version"), pCaps->GetSoftVer(), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++));
- if (pCaps->GetSoftMir())
- FillInfoLine(htiSoftwareInfo, nullptr, TranslateT("Miranda core version"), pCaps->GetSoftMir(), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++));
- }
- }
-
- void FillUserInfo()
- {
- m_tree.SendMsg(WM_SETREDRAW, FALSE, 0);
-
- CleanupInfo(0);
-
- HTREEITEM htiRoot = FillInfoLine(nullptr, IcoLib_GetIconByHandle(ppro->m_hProtoIcon), L"JID", item->jid, sttInfoLineId(0, INFOLINE_NAME), true);
-
- if (MCONTACT hContact = ppro->HContactFromJID(item->jid)) {
- FillAdvStatusInfo(htiRoot, sttInfoLineId(0, INFOLINE_MOOD), hContact, TranslateT("Mood"), ADVSTATUS_MOOD);
- FillAdvStatusInfo(htiRoot, sttInfoLineId(0, INFOLINE_ACTIVITY), hContact, TranslateT("Activity"), ADVSTATUS_ACTIVITY);
- FillAdvStatusInfo(htiRoot, sttInfoLineId(0, INFOLINE_TUNE), hContact, TranslateT("Tune"), ADVSTATUS_TUNE);
- }
-
- // subscription
- switch (item->subscription) {
- case SUB_BOTH:
- FillInfoLine(htiRoot, nullptr, TranslateT("Subscription"), TranslateU("both"), sttInfoLineId(0, INFOLINE_SUBSCRIPTION));
- break;
- case SUB_TO:
- FillInfoLine(htiRoot, nullptr, TranslateT("Subscription"), TranslateU("to"), sttInfoLineId(0, INFOLINE_SUBSCRIPTION));
- break;
- case SUB_FROM:
- FillInfoLine(htiRoot, nullptr, TranslateT("Subscription"), TranslateU("from"), sttInfoLineId(0, INFOLINE_SUBSCRIPTION));
- break;
- default:
- FillInfoLine(htiRoot, nullptr, TranslateT("Subscription"), TranslateU("none"), sttInfoLineId(0, INFOLINE_SUBSCRIPTION));
- break;
- }
-
- // logoff
- char buf[256];
- JABBER_RESOURCE_STATUS *r = item->getTemp();
- if (r->m_dwIdleStartTime != -1) {
- if (r->m_dwIdleStartTime > 0) {
- mir_strncpy(buf, ctime(&r->m_dwIdleStartTime), _countof(buf));
- size_t len = mir_strlen(buf);
- if (len > 0)
- buf[len - 1] = 0;
- }
- else mir_strncpy(buf, TranslateU("<currently online>"), _countof(buf));
-
- FillInfoLine(htiRoot, nullptr,
- (item->jid && strchr(item->jid, '@')) ? TranslateT("Last logoff time") : TranslateT("Uptime"), buf,
- sttInfoLineId(0, INFOLINE_LOGOFF));
- }
-
- if (r->m_szStatusMessage)
- FillInfoLine(htiRoot, nullptr, TranslateT("Logoff message"), r->m_szStatusMessage, sttInfoLineId(0, INFOLINE_LOGOFF_MSG));
-
- // activity
- if (item->m_pLastSeenResource)
- mir_strncpy(buf, item->m_pLastSeenResource->m_szResourceName, _countof(buf));
- else
- mir_strncpy(buf, TranslateU("<no information available>"), _countof(buf));
- FillInfoLine(htiRoot, nullptr, TranslateT("Last active resource"), buf, sttInfoLineId(0, INFOLINE_LASTACTIVE));
-
- // resources
- if (item->arResources.getCount()) {
- for (int i = 0; i < item->arResources.getCount(); i++)
- FillResourceInfo(htiRoot, i + 1);
- }
- else if (!strchr(item->jid, '@') || (r->m_iStatus != ID_STATUS_OFFLINE))
- FillResourceInfo(htiRoot, 0);
-
- CleanupInfo(1);
- m_tree.SendMsg(WM_SETREDRAW, TRUE, 0);
-
- RedrawWindow(m_tree.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE);
- }
-
-public:
- JabberUserInfoDlg(CJabberProto *_ppro) :
- JabberBaseUserInfoDlg(_ppro, IDD_INFO_JABBER),
- m_tree(this, IDC_TV_INFO)
- {
- m_tree.OnBuildMenu = Callback(this, &JabberUserInfoDlg::onMenu_Tree);
- }
-
- bool OnInitDialog() override
- {
- ppro->WindowSubscribe(m_hwnd);
- Window_SetSkinIcon_IcoLib(m_hwnd, SKINICON_OTHER_USERDETAILS);
-
- RECT rc;
- GetClientRect(m_hwnd, &rc);
- MoveWindow(m_tree.GetHwnd(), 5, 5, rc.right - 10, rc.bottom - 10, TRUE);
-
- HIMAGELIST himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR | ILC_COLOR32 | ILC_MASK, 5, 1);
- ImageList_AddSkinIcon(himl, SKINICON_OTHER_SMALLDOT);
- TreeView_SetImageList(m_tree.GetHwnd(), himl, TVSIL_NORMAL);
-
- WindowList_Add(hUserInfoList, m_hwnd, m_hContact);
- return true;
- }
-
- void OnDestroy() override
- {
- ppro->WindowUnsubscribe(m_hwnd);
- WindowList_Remove(hUserInfoList, m_hwnd);
- ImageList_Destroy(m_tree.SetImageList(nullptr, TVSIL_NORMAL));
- Window_FreeIcon_IcoLib(m_hwnd);
- }
-
- int Resizer(UTILRESIZECONTROL*) override
- {
- return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
- }
-
- bool OnRefresh() override
- {
- if (item == nullptr) {
- ptrA jid(ppro->getUStringA(m_hContact, "jid"));
- if (jid == nullptr)
- return false;
-
- if (ppro->m_bJabberOnline)
- if (!(item = ppro->ListGetItemPtr(LIST_VCARD_TEMP, jid)))
- item = ppro->ListGetItemPtr(LIST_ROSTER, jid);
-
- if (item == nullptr) {
- m_tree.DeleteAllItems();
- HTREEITEM htiRoot = FillInfoLine(nullptr, IcoLib_GetIconByHandle(ppro->m_hProtoIcon), L"JID", jid, sttInfoLineId(0, INFOLINE_NAME), true);
- FillInfoLine(htiRoot, g_plugin.getIcon(IDI_VCARD), nullptr, TranslateU("Please switch online to see more details."));
- return false;
- }
- }
- FillUserInfo();
- return false;
- }
-
- ////////////////////////////////////////////////////////////////////////////////////////
- // Context menu
-
- void GetNodeText(HTREEITEM hti, CMStringW &buf, int indent = 0)
- {
- for (int i = 0; i < indent; i++)
- buf.AppendChar('\t');
-
- wchar_t wszText[256];
- TVITEMEX tvi = {};
- tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_STATE;
- tvi.hItem = hti;
- tvi.cchTextMax = _countof(wszText);
- tvi.pszText = wszText;
- if (!m_tree.GetItem(&tvi)) // failure, maybe item was removed...
- return;
-
- buf.Append(wszText);
- buf.Append(L"\r\n");
-
- if (tvi.state & TVIS_EXPANDED)
- for (hti = m_tree.GetChild(hti); hti; hti = m_tree.GetNextSibling(hti))
- GetNodeText(hti, buf, indent + 1);
- }
-
- void onMenu_Tree(CContextMenuPos *pos)
- {
- if (!pos->hItem)
- return;
-
- HMENU hMenu = CreatePopupMenu();
- AppendMenu(hMenu, MF_STRING, (UINT_PTR)1, TranslateT("Copy"));
- AppendMenu(hMenu, MF_STRING, (UINT_PTR)2, TranslateT("Copy only this value"));
- AppendMenu(hMenu, MF_SEPARATOR, 0, nullptr);
- AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel"));
- int nReturnCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD, pos->pt.x, pos->pt.y, 0, m_hwnd, nullptr);
- if (nReturnCmd == 1) {
- CMStringW buf;
- GetNodeText(pos->hItem, buf);
- Utils_ClipboardCopy(buf);
- }
- else if (nReturnCmd == 2) {
- wchar_t szBuffer[1024];
- TVITEMEX tvi = { 0 };
- tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_STATE;
- tvi.hItem = pos->hItem;
- tvi.cchTextMax = _countof(szBuffer);
- tvi.pszText = szBuffer;
- if (m_tree.GetItem(&tvi)) {
- if (wchar_t *str = wcsstr(szBuffer, L": "))
- Utils_ClipboardCopy(str + 2);
- else
- Utils_ClipboardCopy(szBuffer);
- }
- }
- DestroyMenu(hMenu);
- }
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// JabberUserPhotoDlgProc - Jabber photo dialog
-
-class JabberUserPhotoDlg : public JabberBaseUserInfoDlg
-{
- HBITMAP hBitmap = nullptr;
-
- CCtrlMButton btnSave;
-
- UI_MESSAGE_MAP(JabberUserInfoDlg, JabberBaseUserInfoDlg);
- UI_MESSAGE(WM_PAINT, OnPaint);
- UI_MESSAGE_MAP_END();
-
- char *GetFileName() const
- {
- ptrA jid(ppro->getUStringA(m_hContact, "jid"));
- if (jid != nullptr) {
- JABBER_LIST_ITEM *item = ppro->ListGetItemPtr(LIST_VCARD_TEMP, jid);
- if (item == nullptr)
- item = ppro->ListGetItemPtr(LIST_ROSTER, jid);
- if (item != nullptr)
- return item->photoFileName;
- }
-
- return nullptr;
- }
-
-public:
- JabberUserPhotoDlg(CJabberProto *_ppro) :
- JabberBaseUserInfoDlg(_ppro, IDD_VCARD_PHOTO),
- btnSave(this, IDC_SAVE, g_plugin.getIcon(IDI_SAVE), LPGEN("Save"))
- {
- btnSave.OnClick = Callback(this, &JabberUserPhotoDlg::onClick_Save);
- }
-
- bool OnInitDialog() override
- {
- ShowWindow(GetDlgItem(m_hwnd, IDC_LOAD), SW_HIDE);
- ShowWindow(GetDlgItem(m_hwnd, IDC_DELETE), SW_HIDE);
- return true;
- }
-
- void OnDestroy() override
- {
- if (hBitmap) {
- ppro->debugLogA("Delete bitmap");
- DeleteObject(hBitmap);
- }
- }
-
- bool IsEmpty() const override
- {
- return mir_strlen(GetFileName()) == 0;
- }
-
- bool OnRefresh() override
- {
- if (hBitmap) {
- DeleteObject(hBitmap);
- hBitmap = nullptr;
- }
- btnSave.Hide();
-
- char *pszFileName = GetFileName();
- if (mir_strlen(pszFileName)) {
- ppro->debugLogA("Showing picture from %s", pszFileName);
- hBitmap = Bitmap_Load(Utf2T(pszFileName));
- FreeImage_Premultiply(hBitmap);
- btnSave.Show();
- }
-
- InvalidateRect(m_hwnd, nullptr, TRUE);
- UpdateWindow(m_hwnd);
- return true;
- }
-
- void onClick_Save(CCtrlButton *)
- {
- wchar_t szFilter[512];
-
- ptrA jid(ppro->getUStringA(m_hContact, "jid"));
- if (jid == nullptr)
- return;
-
- JABBER_LIST_ITEM *item = ppro->ListGetItemPtr(LIST_VCARD_TEMP, jid);
- if (item == nullptr)
- if ((item = ppro->ListGetItemPtr(LIST_ROSTER, jid)) == nullptr)
- return;
-
- switch (ProtoGetAvatarFileFormat(Utf2T(item->photoFileName))) {
- case PA_FORMAT_BMP:
- mir_snwprintf(szFilter, L"BMP %s (*.bmp)%c*.BMP", TranslateT("format"), 0);
- break;
-
- case PA_FORMAT_GIF:
- mir_snwprintf(szFilter, L"GIF %s (*.gif)%c*.GIF", TranslateT("format"), 0);
- break;
-
- case PA_FORMAT_JPEG:
- mir_snwprintf(szFilter, L"JPEG %s (*.jpg;*.jpeg)%c*.JPG;*.JPEG", TranslateT("format"), 0);
- break;
-
- default:
- mir_snwprintf(szFilter, L"%s (*.*)%c*.*", TranslateT("Unknown format"), 0);
- }
-
- wchar_t szFileName[MAX_PATH]; szFileName[0] = '\0';
- OPENFILENAME ofn = { 0 };
- ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
- ofn.hwndOwner = m_hwnd;
- ofn.lpstrFilter = szFilter;
- ofn.lpstrFile = szFileName;
- ofn.nMaxFile = _MAX_PATH;
- ofn.Flags = OFN_OVERWRITEPROMPT;
- if (GetSaveFileName(&ofn)) {
- ppro->debugLogW(L"File selected is %s", szFileName);
- CopyFile(Utf2T(item->photoFileName), szFileName, FALSE);
- }
- }
-
- INT_PTR OnPaint(UINT, WPARAM, LPARAM)
- {
- if (!ppro->m_bJabberOnline)
- SetDlgItemText(m_hwnd, IDC_CANVAS, TranslateT("<Photo not available while offline>"));
- else if (!hBitmap)
- SetDlgItemText(m_hwnd, IDC_CANVAS, TranslateT("<No photo>"));
- else {
- BITMAP bm;
- POINT ptSize, ptOrg, pt, ptFitSize;
- RECT rect;
-
- SetDlgItemTextA(m_hwnd, IDC_CANVAS, "");
- HWND hwndCanvas = GetDlgItem(m_hwnd, IDC_CANVAS);
- HDC hdcCanvas = GetDC(hwndCanvas);
- HDC hdcMem = CreateCompatibleDC(hdcCanvas);
- SelectObject(hdcMem, hBitmap);
- SetMapMode(hdcMem, GetMapMode(hdcCanvas));
- GetObject(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
- ptSize.x = bm.bmWidth;
- ptSize.y = bm.bmHeight;
- DPtoLP(hdcCanvas, &ptSize, 1);
- ptOrg.x = ptOrg.y = 0;
- DPtoLP(hdcMem, &ptOrg, 1);
- GetClientRect(hwndCanvas, &rect);
- InvalidateRect(hwndCanvas, nullptr, TRUE);
- UpdateWindow(hwndCanvas);
- if (ptSize.x <= rect.right && ptSize.y <= rect.bottom) {
- pt.x = (rect.right - ptSize.x) / 2;
- pt.y = (rect.bottom - ptSize.y) / 2;
- ptFitSize = ptSize;
- }
- else {
- if (((float)(ptSize.x - rect.right)) / ptSize.x > ((float)(ptSize.y - rect.bottom)) / ptSize.y) {
- ptFitSize.x = rect.right;
- ptFitSize.y = (ptSize.y * rect.right) / ptSize.x;
- pt.x = 0;
- pt.y = (rect.bottom - ptFitSize.y) / 2;
- }
- else {
- ptFitSize.x = (ptSize.x * rect.bottom) / ptSize.y;
- ptFitSize.y = rect.bottom;
- pt.x = (rect.right - ptFitSize.x) / 2;
- pt.y = 0;
- }
- }
-
- RECT rc;
- if (IsThemeActive()) {
- GetClientRect(hwndCanvas, &rc);
- DrawThemeParentBackground(hwndCanvas, hdcCanvas, &rc);
- }
- else {
- GetClientRect(hwndCanvas, &rc);
- FillRect(hdcCanvas, &rc, (HBRUSH)GetSysColorBrush(COLOR_BTNFACE));
- }
-
- if (bm.bmBitsPixel == 32) {
- BLENDFUNCTION bf = { 0 };
- bf.AlphaFormat = AC_SRC_ALPHA;
- bf.BlendOp = AC_SRC_OVER;
- bf.SourceConstantAlpha = 255;
- GdiAlphaBlend(hdcCanvas, pt.x, pt.y, ptFitSize.x, ptFitSize.y, hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y, bf);
- }
- else {
- SetStretchBltMode(hdcCanvas, COLORONCOLOR);
- StretchBlt(hdcCanvas, pt.x, pt.y, ptFitSize.x, ptFitSize.y, hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y, SRCCOPY);
- }
-
- DeleteDC(hdcMem);
- }
- return FALSE;
- }
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// JabberUserPhotoDlgProc - Jabber photo dialog
-
-static int EnumOwnSessions(const char *szSetting, void *param)
-{
- auto *pList = (LIST<char>*)param;
-
- if (!memcmp(szSetting, omemo::DevicePrefix, sizeof(omemo::DevicePrefix)-1))
- if (szSetting[sizeof(omemo::DevicePrefix)] != 0)
- pList->insert(mir_strdup(szSetting));
-
- return 0;
-}
-
-static int EnumOmemoSessions(const char *szSetting, void *param)
-{
- auto *pList = (LIST<char>*)param;
-
- if (!memcmp(szSetting, omemo::IdentityPrefix, sizeof(omemo::IdentityPrefix) - 1))
- pList->insert(mir_strdup(szSetting + sizeof(omemo::IdentityPrefix)));
-
- return 0;
-}
-
-class JabberUserOmemoDlg : public JabberBaseUserInfoDlg
-{
- CCtrlListView m_list;
-
- void AddListItem(const CMStringA &pszStr1, const wchar_t *pszStr2, const CMStringA &pszStr3)
- {
- LVITEM lvi = {};
- lvi.mask = LVIF_TEXT;
- lvi.pszText = mir_a2u(pszStr1);
- lvi.iItem = 100500;
- int idx = m_list.InsertItem(&lvi);
- mir_free(lvi.pszText);
-
- m_list.SetItemText(idx, 1, (wchar_t *)pszStr2);
- CMStringW fp = omemo::FormatFingerprint(pszStr3);
- m_list.SetItemText(idx, 2, fp.GetBuffer());
- }
-
-public:
- JabberUserOmemoDlg(CJabberProto *_ppro) :
- JabberBaseUserInfoDlg(_ppro, IDD_INFO_OMEMO),
- m_list(this, IDC_LIST)
- {
- }
-
- bool OnInitDialog() override
- {
- LV_COLUMN lvc = {};
- lvc.mask = LVCF_TEXT | LVCF_WIDTH;
-
- lvc.cx = 90;
- lvc.pszText = TranslateT("Device ID");
- m_list.InsertColumn(1, &lvc);
-
- lvc.cx = 80;
- lvc.pszText = TranslateT("Status");
- m_list.InsertColumn(2, &lvc);
-
- lvc.cx = 550;
- lvc.pszText = TranslateT("Fingerprint");
- m_list.InsertColumn(3, &lvc);
-
- if (m_hContact == 0)
- OnRefresh();
- return true;
- }
-
- int Resizer(UTILRESIZECONTROL*) override
- {
- return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
- }
-
- bool OnRefresh() override
- {
- m_list.DeleteAllItems();
-
- if (m_hContact == 0) {
- // GetOwnDeviceId() creates own keys if they don't exist
- CMStringA str1(FORMAT, "%d", ppro->m_omemo.GetOwnDeviceId());
- CMStringA str2(ppro->getMStringA("OmemoFingerprintOwn"));
- AddListItem(str1, TranslateT("Own device"), str2);
- }
-
- for (int i = 0;; i++) {
- CMStringA szSetting(FORMAT, "%s%d", omemo::DevicePrefix, i);
- uint32_t device_id = ppro->getDword(m_hContact, szSetting, 0);
- if (device_id == 0)
- break;
-
- char *jiddev = ppro->getStringA(m_hContact, "jid");
- if (jiddev == 0)
- continue;
-
- size_t len = strlen(jiddev);
- jiddev = (char *)mir_realloc(jiddev, len + sizeof(int32_t));
- memcpy(jiddev + len, &device_id, sizeof(int32_t));
-
- szSetting = omemo::IdentityPrefix;
- szSetting.Append(ptrA(mir_base64_encode(jiddev, len + sizeof(int32_t))));
- mir_free(jiddev);
-
- const wchar_t *pwszStatus = L"";
- CMStringA fp_hex;
- DBVARIANT dbv = { 0 };
- dbv.type = DBVT_BLOB;
- db_get(m_hContact, ppro->m_szModuleName, szSetting, &dbv);
- if (dbv.cpbVal == 33) {
- fp_hex.Truncate(33 * 2);
- bin2hex(dbv.pbVal, 33, fp_hex.GetBuffer());
- uint8_t trusted = ppro->getByte(m_hContact, "OmemoFingerprintTrusted_" + fp_hex);
- pwszStatus = trusted ? TranslateT("Trusted") : TranslateT("UNTRUSTED");
- //TODO: 3 states Trusted, Untrusted, TOFU
- }
- else if (dbv.cpbVal)
- pwszStatus = TranslateT("Unknown");
-
- db_free(&dbv);
-
- AddListItem(CMStringA(FORMAT, "%d", device_id), pwszStatus, fp_hex);
- }
- return false;
- }
-};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// OnInfoInit - initializes user info option dialogs
-
-int CJabberProto::OnUserInfoInit(WPARAM wParam, LPARAM hContact)
-{
- if (!Proto_GetAccount(m_szModuleName))
- return 0;
-
- if (hContact == 0) {
- // Show our vcard
- OnUserInfoInit_VCard(wParam, hContact);
- return 0;
- }
-
- char *szProto = Proto_GetBaseAccountName(hContact);
- if (szProto != nullptr && !mir_strcmp(szProto, m_szModuleName)) {
- USERINFOPAGE uip = {};
- uip.dwInitParam = (LPARAM)this;
- uip.flags = ODPF_UNICODE | ODPF_USERINFOTAB | ODPF_ICON;
- uip.szGroup.w = m_tszUserName;
- uip.dwInitParam = (LPARAM)Skin_GetProtoIcon(m_szModuleName, ID_STATUS_ONLINE);
-
- uip.pDialog = new JabberUserInfoDlg(this);
- uip.position = -2000000000;
- uip.szTitle.w = LPGENW("Account");
- g_plugin.addUserInfo(wParam, &uip);
-
- uip.pDialog = new JabberUserPhotoDlg(this);
- uip.position = 2000000000;
- uip.szTitle.w = LPGENW("Photo");
- g_plugin.addUserInfo(wParam, &uip);
-
- CheckOmemoUserInfo(wParam, uip);
- }
-
- return 0;
-}
-
-void CJabberProto::CheckOmemoUserInfo(WPARAM wParam, USERINFOPAGE &uip)
-{
- if (m_bUseOMEMO) {
- uip.pDialog = new JabberUserOmemoDlg(this);
- uip.position = 2000000001;
- uip.szTitle.w = L"OMEMO";
- g_plugin.addUserInfo(wParam, &uip);
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// JabberUserInfoUpdate
-
-void JabberUserInfoInit()
-{
- hUserInfoList = WindowList_Create();
-}
-
-void JabberUserInfoUninit()
-{
- WindowList_Destroy(hUserInfoList);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// JabberUserInfoUpdate
-
-void JabberUserInfoUpdate(MCONTACT hContact)
-{
- if (!hContact)
- WindowList_BroadcastAsync(hUserInfoList, WM_PROTO_REFRESH, 0, 0);
- else if (HWND hwnd = WindowList_Find(hUserInfoList, hContact))
- PostMessage(hwnd, WM_PROTO_REFRESH, 0, 0);
-}
+/*
+
+Jabber Protocol Plugin for Miranda NG
+
+Copyright (c) 2002-04 Santithorn Bunchua
+Copyright (c) 2005-12 George Hazan
+Copyright (c) 2007 Maxim Mluhov
+Copyright (C) 2012-23 Miranda NG team
+
+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; either version 2
+of the License, or (at your option) any later version.
+
+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, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+#include "stdafx.h"
+
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+
+#include "jabber_list.h"
+
+static MWindowList hUserInfoList = nullptr;
+
+class JabberBaseUserInfoDlg : public CUserInfoPageDlg
+{
+ INT_PTR DoRefresh(UINT, WPARAM, LPARAM)
+ {
+ OnRefresh();
+ return 0;
+ }
+
+protected:
+ UI_MESSAGE_MAP(JabberBaseUserInfoDlg, CUserInfoPageDlg);
+ UI_MESSAGE(WM_PROTO_REFRESH, DoRefresh);
+ UI_MESSAGE(WM_JABBER_REFRESH_VCARD, DoRefresh);
+ UI_MESSAGE_MAP_END();
+
+ CJabberProto *ppro;
+
+ JabberBaseUserInfoDlg(CJabberProto *_ppro, int dlgId) :
+ CUserInfoPageDlg(g_plugin, dlgId),
+ ppro(_ppro)
+ {}
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberUserInfoDlgProc - main user info dialog
+
+enum
+{
+ INFOLINE_DELETE = 0x80000000,
+ INFOLINE_MASK = 0x7fffffff,
+ INFOLINE_BAD_ID = 0x7fffffff,
+
+ INFOLINE_NAME = 1,
+ INFOLINE_MOOD,
+ INFOLINE_ACTIVITY,
+ INFOLINE_TUNE,
+ INFOLINE_OFFLINE,
+ INFOLINE_MESSAGE,
+ INFOLINE_SOFTWARE,
+ INFOLINE_VERSION,
+ INFOLINE_SYSTEM,
+ INFOLINE_PRIORITY,
+ INFOLINE_IDLE,
+ INFOLINE_CAPS,
+ INFOLINE_SOFTWARE_INFORMATION,
+ INFOLINE_SUBSCRIPTION,
+ INFOLINE_LOGOFF,
+ INFOLINE_LOGOFF_MSG,
+ INFOLINE_LASTACTIVE,
+};
+
+__forceinline uint32_t sttInfoLineId(uint32_t res, uint32_t type, uint32_t line = 0)
+{
+ return
+ (type << 24) & 0x7f000000 |
+ (res << 12) & 0x00fff000 |
+ (line) & 0x00000fff;
+}
+
+class JabberUserInfoDlg : public JabberBaseUserInfoDlg
+{
+ JABBER_LIST_ITEM *item = nullptr;
+ int resourcesCount = -1;
+
+ CCtrlTreeView m_tree;
+
+ UI_MESSAGE_MAP(JabberUserInfoDlg, JabberBaseUserInfoDlg);
+ UI_MESSAGE(WM_PROTO_CHECK_ONLINE, OnCheckOnline);
+ UI_MESSAGE_MAP_END();
+
+ INT_PTR OnCheckOnline(UINT, WPARAM, LPARAM)
+ {
+ if (!ppro->m_bJabberOnline)
+ item = nullptr;
+ else
+ OnRefresh();
+ return 0;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////
+ // User information block
+
+ void CleanupInfo(int stage)
+ {
+ HTREEITEM hItem = m_tree.GetRoot();
+ while (hItem) {
+ TVITEMEX tvi = { 0 };
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = hItem;
+ m_tree.GetItem(&tvi);
+
+ switch (stage) {
+ case 0:
+ tvi.lParam |= INFOLINE_DELETE;
+ m_tree.SetItem(&tvi);
+ break;
+
+ case 1:
+ if (tvi.lParam & INFOLINE_DELETE) {
+ hItem = m_tree.GetNextSibling(hItem);
+ m_tree.DeleteItem(tvi.hItem);
+ continue;
+ }
+ break;
+ }
+
+ HTREEITEM hItemTmp = nullptr;
+ if (hItemTmp = m_tree.GetChild(hItem))
+ hItem = hItemTmp;
+ else if (hItemTmp = m_tree.GetNextSibling(hItem))
+ hItem = hItemTmp;
+ else {
+ while (true) {
+ if (!(hItem = m_tree.GetParent(hItem))) break;
+ if (hItemTmp = m_tree.GetNextSibling(hItem)) {
+ hItem = hItemTmp;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ HTREEITEM FindInfoLine(HTREEITEM htiRoot, LPARAM id = INFOLINE_BAD_ID)
+ {
+ if (id == INFOLINE_BAD_ID) return nullptr;
+ for (HTREEITEM hti = m_tree.GetChild(htiRoot); hti; hti = m_tree.GetNextSibling(hti)) {
+ TVITEMEX tvi = { 0 };
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = hti;
+ m_tree.GetItem(&tvi);
+ if ((tvi.lParam&INFOLINE_MASK) == (id&INFOLINE_MASK))
+ return hti;
+ }
+ return nullptr;
+ }
+
+ HTREEITEM FillInfoLine(HTREEITEM htiRoot, HICON hIcon, const wchar_t *title, const char *value, LPARAM id = INFOLINE_BAD_ID, bool expand = false)
+ {
+ HTREEITEM hti = FindInfoLine(htiRoot, id);
+
+ Utf2T wszValue(value);
+ const wchar_t *pwszValue = (value == nullptr) ? TranslateT("<not specified>") : wszValue;
+ wchar_t buf[256];
+ if (title)
+ mir_snwprintf(buf, L"%s: %s", title, pwszValue);
+ else
+ mir_wstrncpy(buf, pwszValue, _countof(buf));
+
+ TVINSERTSTRUCT tvis = {};
+ tvis.hParent = htiRoot;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.itemex.mask = TVIF_TEXT | TVIF_PARAM;
+ tvis.itemex.pszText = buf;
+ tvis.itemex.lParam = id;
+
+ if (hIcon) {
+ HIMAGELIST himl = m_tree.GetImageList(TVSIL_NORMAL);
+ tvis.itemex.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tvis.itemex.iImage =
+ tvis.itemex.iSelectedImage = ImageList_AddIcon(himl, hIcon);
+ IcoLib_ReleaseIcon(hIcon);
+ }
+
+ if (hti) {
+ tvis.itemex.mask |= TVIF_HANDLE;
+ tvis.itemex.hItem = hti;
+ m_tree.SetItem(&tvis.itemex);
+ }
+ else {
+ tvis.itemex.mask |= TVIF_STATE;
+ tvis.itemex.stateMask = TVIS_EXPANDED;
+ tvis.itemex.state = expand ? TVIS_EXPANDED : 0;
+ hti = m_tree.InsertItem(&tvis);
+ }
+
+ return hti;
+ }
+
+ void FillAdvStatusInfo(HTREEITEM htiRoot, uint32_t dwInfoLine, MCONTACT hContact, wchar_t *szTitle, char *pszSlot)
+ {
+ ptrA szAdvStatusIcon(ppro->ReadAdvStatusA(hContact, pszSlot, ADVSTATUS_VAL_ICON));
+ ptrW szAdvStatusTitle(ppro->ReadAdvStatusT(hContact, pszSlot, ADVSTATUS_VAL_TITLE));
+ ptrW szAdvStatusText(ppro->ReadAdvStatusT(hContact, pszSlot, ADVSTATUS_VAL_TEXT));
+
+ if (szAdvStatusIcon && szAdvStatusTitle && *szAdvStatusTitle) {
+ wchar_t szText[2048];
+ if (szAdvStatusText && *szAdvStatusText)
+ mir_snwprintf(szText, L"%s (%s)", TranslateW(szAdvStatusTitle), szAdvStatusText.get());
+ else
+ wcsncpy_s(szText, TranslateW(szAdvStatusTitle), _TRUNCATE);
+ FillInfoLine(htiRoot, IcoLib_GetIcon(szAdvStatusIcon), szTitle, T2Utf(szText), dwInfoLine);
+ }
+ }
+
+ void FillResourceInfo(HTREEITEM htiRoot, int resource)
+ {
+ HTREEITEM htiResource = htiRoot;
+ pResourceStatus r = resource ? item->arResources[resource - 1] : item->getTemp();
+
+ if (r->m_szResourceName && *r->m_szResourceName)
+ htiResource = FillInfoLine(htiRoot, Skin_LoadProtoIcon(ppro->m_szModuleName, r->m_iStatus),
+ TranslateT("Resource"), r->m_szResourceName, sttInfoLineId(resource, INFOLINE_NAME), true);
+
+ // StatusMsg
+ FillInfoLine(htiResource, nullptr /*Skin_LoadIcon(SKINICON_EVENT_MESSAGE)*/,
+ TranslateT("Message"), r->m_szStatusMessage,
+ sttInfoLineId(resource, INFOLINE_MESSAGE));
+
+ // Software
+ if (CJabberClientPartialCaps *pCaps = r->m_pCaps) {
+ HICON hIcon = nullptr;
+
+ if (ServiceExists(MS_FP_GETCLIENTICONT)) {
+ if (pCaps->GetSoft()) {
+ wchar_t buf[256];
+ mir_snwprintf(buf, L"%s %s", pCaps->GetSoft(), pCaps->GetSoftVer());
+ hIcon = Finger_GetClientIcon(buf, 0);
+ }
+ }
+
+ FillInfoLine(htiResource, hIcon, TranslateT("Software"), pCaps->GetSoft(), sttInfoLineId(resource, INFOLINE_SOFTWARE));
+
+ // Version
+ FillInfoLine(htiResource, nullptr, TranslateT("Version"), pCaps->GetSoftMir() ? pCaps->GetSoftMir() : pCaps->GetSoftVer(), sttInfoLineId(resource, INFOLINE_VERSION));
+
+ // System
+ FillInfoLine(htiResource, nullptr, TranslateT("System"), pCaps->GetOsVer() ? pCaps->GetOsVer() : pCaps->GetOs(), sttInfoLineId(resource, INFOLINE_SYSTEM));
+
+ if (hIcon)
+ DestroyIcon(hIcon);
+ }
+
+ // Resource priority
+ char buf[256];
+ itoa(r->m_iPriority, buf, 10);
+ FillInfoLine(htiResource, nullptr, TranslateT("Resource priority"), buf, sttInfoLineId(resource, INFOLINE_PRIORITY));
+
+ // Idle
+ if (r->m_dwIdleStartTime != -1) {
+ if (r->m_dwIdleStartTime != 0) {
+ mir_strncpy(buf, ctime(&r->m_dwIdleStartTime), _countof(buf));
+ size_t len = mir_strlen(buf);
+ if (len > 0)
+ buf[len - 1] = 0;
+ }
+ else mir_strncpy(buf, TranslateU("<currently online>"), _countof(buf));
+
+ FillInfoLine(htiResource, nullptr, TranslateT("Last activity"), buf, sttInfoLineId(resource, INFOLINE_IDLE));
+ }
+
+ // caps
+ JabberCapsBits jcb = ppro->GetResourceCapabilities(MakeJid(item->jid, r->m_szResourceName), r);
+ if (!(jcb & JABBER_RESOURCE_CAPS_ERROR)) {
+ HTREEITEM htiCaps = FillInfoLine(htiResource, IcoLib_GetIconByHandle(ppro->m_hProtoIcon), nullptr, TranslateU("Client capabilities"), sttInfoLineId(resource, INFOLINE_CAPS));
+ int i;
+ for (i = 0; i < g_cJabberFeatCapPairs; i++)
+ if (jcb & g_JabberFeatCapPairs[i].jcbCap) {
+ char szDescription[1024];
+ if (g_JabberFeatCapPairs[i].tszDescription)
+ mir_snprintf(szDescription, "%s (%s)", TranslateU(g_JabberFeatCapPairs[i].tszDescription), g_JabberFeatCapPairs[i].szFeature);
+ else
+ strncpy_s(szDescription, g_JabberFeatCapPairs[i].szFeature, _TRUNCATE);
+ FillInfoLine(htiCaps, nullptr, nullptr, szDescription, sttInfoLineId(resource, INFOLINE_CAPS, i));
+ }
+
+ for (auto &it : ppro->m_lstJabberFeatCapPairsDynamic) {
+ if (jcb & it->jcbCap) {
+ char szDescription[1024];
+ if (it->szDescription)
+ mir_snprintf(szDescription, "%s (%s)", TranslateU(it->szDescription), it->szFeature);
+ else
+ strncpy_s(szDescription, it->szFeature, _TRUNCATE);
+ FillInfoLine(htiCaps, nullptr, nullptr, szDescription, sttInfoLineId(resource, INFOLINE_CAPS, i++));
+ }
+ }
+ }
+
+ // Software info
+ HTREEITEM htiSoftwareInfo = FillInfoLine(htiResource, IcoLib_GetIconByHandle(ppro->m_hProtoIcon), nullptr, TranslateU("Software information"), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION));
+ int nLineId = 0;
+ if (CJabberClientPartialCaps *pCaps = r->m_pCaps) {
+ if (pCaps->GetOs())
+ FillInfoLine(htiSoftwareInfo, nullptr, TranslateT("Operating system"), pCaps->GetOs(), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++));
+ if (pCaps->GetOsVer())
+ FillInfoLine(htiSoftwareInfo, nullptr, TranslateT("Operating system version"), pCaps->GetOsVer(), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++));
+ if (pCaps->GetSoft())
+ FillInfoLine(htiSoftwareInfo, nullptr, TranslateT("Software"), pCaps->GetSoft(), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++));
+ if (pCaps->GetSoftVer())
+ FillInfoLine(htiSoftwareInfo, nullptr, TranslateT("Software version"), pCaps->GetSoftVer(), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++));
+ if (pCaps->GetSoftMir())
+ FillInfoLine(htiSoftwareInfo, nullptr, TranslateT("Miranda core version"), pCaps->GetSoftMir(), sttInfoLineId(resource, INFOLINE_SOFTWARE_INFORMATION, nLineId++));
+ }
+ }
+
+ void FillUserInfo()
+ {
+ m_tree.SendMsg(WM_SETREDRAW, FALSE, 0);
+
+ CleanupInfo(0);
+
+ HTREEITEM htiRoot = FillInfoLine(nullptr, IcoLib_GetIconByHandle(ppro->m_hProtoIcon), L"JID", item->jid, sttInfoLineId(0, INFOLINE_NAME), true);
+
+ if (MCONTACT hContact = ppro->HContactFromJID(item->jid)) {
+ FillAdvStatusInfo(htiRoot, sttInfoLineId(0, INFOLINE_MOOD), hContact, TranslateT("Mood"), ADVSTATUS_MOOD);
+ FillAdvStatusInfo(htiRoot, sttInfoLineId(0, INFOLINE_ACTIVITY), hContact, TranslateT("Activity"), ADVSTATUS_ACTIVITY);
+ FillAdvStatusInfo(htiRoot, sttInfoLineId(0, INFOLINE_TUNE), hContact, TranslateT("Tune"), ADVSTATUS_TUNE);
+ }
+
+ // subscription
+ switch (item->subscription) {
+ case SUB_BOTH:
+ FillInfoLine(htiRoot, nullptr, TranslateT("Subscription"), TranslateU("both"), sttInfoLineId(0, INFOLINE_SUBSCRIPTION));
+ break;
+ case SUB_TO:
+ FillInfoLine(htiRoot, nullptr, TranslateT("Subscription"), TranslateU("to"), sttInfoLineId(0, INFOLINE_SUBSCRIPTION));
+ break;
+ case SUB_FROM:
+ FillInfoLine(htiRoot, nullptr, TranslateT("Subscription"), TranslateU("from"), sttInfoLineId(0, INFOLINE_SUBSCRIPTION));
+ break;
+ default:
+ FillInfoLine(htiRoot, nullptr, TranslateT("Subscription"), TranslateU("none"), sttInfoLineId(0, INFOLINE_SUBSCRIPTION));
+ break;
+ }
+
+ // logoff
+ char buf[256];
+ JABBER_RESOURCE_STATUS *r = item->getTemp();
+ if (r->m_dwIdleStartTime != -1) {
+ if (r->m_dwIdleStartTime > 0) {
+ mir_strncpy(buf, ctime(&r->m_dwIdleStartTime), _countof(buf));
+ size_t len = mir_strlen(buf);
+ if (len > 0)
+ buf[len - 1] = 0;
+ }
+ else mir_strncpy(buf, TranslateU("<currently online>"), _countof(buf));
+
+ FillInfoLine(htiRoot, nullptr,
+ (item->jid && strchr(item->jid, '@')) ? TranslateT("Last logoff time") : TranslateT("Uptime"), buf,
+ sttInfoLineId(0, INFOLINE_LOGOFF));
+ }
+
+ if (r->m_szStatusMessage)
+ FillInfoLine(htiRoot, nullptr, TranslateT("Logoff message"), r->m_szStatusMessage, sttInfoLineId(0, INFOLINE_LOGOFF_MSG));
+
+ // activity
+ if (item->m_pLastSeenResource)
+ mir_strncpy(buf, item->m_pLastSeenResource->m_szResourceName, _countof(buf));
+ else
+ mir_strncpy(buf, TranslateU("<no information available>"), _countof(buf));
+ FillInfoLine(htiRoot, nullptr, TranslateT("Last active resource"), buf, sttInfoLineId(0, INFOLINE_LASTACTIVE));
+
+ // resources
+ if (item->arResources.getCount()) {
+ for (int i = 0; i < item->arResources.getCount(); i++)
+ FillResourceInfo(htiRoot, i + 1);
+ }
+ else if (!strchr(item->jid, '@') || (r->m_iStatus != ID_STATUS_OFFLINE))
+ FillResourceInfo(htiRoot, 0);
+
+ CleanupInfo(1);
+ m_tree.SendMsg(WM_SETREDRAW, TRUE, 0);
+
+ RedrawWindow(m_tree.GetHwnd(), nullptr, nullptr, RDW_INVALIDATE);
+ }
+
+public:
+ JabberUserInfoDlg(CJabberProto *_ppro) :
+ JabberBaseUserInfoDlg(_ppro, IDD_INFO_JABBER),
+ m_tree(this, IDC_TV_INFO)
+ {
+ m_tree.OnBuildMenu = Callback(this, &JabberUserInfoDlg::onMenu_Tree);
+ }
+
+ bool OnInitDialog() override
+ {
+ ppro->WindowSubscribe(m_hwnd);
+ Window_SetSkinIcon_IcoLib(m_hwnd, SKINICON_OTHER_USERDETAILS);
+
+ RECT rc;
+ GetClientRect(m_hwnd, &rc);
+ MoveWindow(m_tree.GetHwnd(), 5, 5, rc.right - 10, rc.bottom - 10, TRUE);
+
+ HIMAGELIST himl = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR | ILC_COLOR32 | ILC_MASK, 5, 1);
+ ImageList_AddSkinIcon(himl, SKINICON_OTHER_SMALLDOT);
+ TreeView_SetImageList(m_tree.GetHwnd(), himl, TVSIL_NORMAL);
+
+ WindowList_Add(hUserInfoList, m_hwnd, m_hContact);
+ return true;
+ }
+
+ void OnDestroy() override
+ {
+ ppro->WindowUnsubscribe(m_hwnd);
+ WindowList_Remove(hUserInfoList, m_hwnd);
+ ImageList_Destroy(m_tree.SetImageList(nullptr, TVSIL_NORMAL));
+ Window_FreeIcon_IcoLib(m_hwnd);
+ }
+
+ int Resizer(UTILRESIZECONTROL*) override
+ {
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
+ }
+
+ bool OnRefresh() override
+ {
+ if (item == nullptr) {
+ ptrA jid(ppro->getUStringA(m_hContact, "jid"));
+ if (jid == nullptr)
+ return false;
+
+ if (ppro->m_bJabberOnline)
+ if (!(item = ppro->ListGetItemPtr(LIST_VCARD_TEMP, jid)))
+ item = ppro->ListGetItemPtr(LIST_ROSTER, jid);
+
+ if (item == nullptr) {
+ m_tree.DeleteAllItems();
+ HTREEITEM htiRoot = FillInfoLine(nullptr, IcoLib_GetIconByHandle(ppro->m_hProtoIcon), L"JID", jid, sttInfoLineId(0, INFOLINE_NAME), true);
+ FillInfoLine(htiRoot, g_plugin.getIcon(IDI_VCARD), nullptr, TranslateU("Please switch online to see more details."));
+ return false;
+ }
+ }
+ FillUserInfo();
+ return false;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////
+ // Context menu
+
+ void GetNodeText(HTREEITEM hti, CMStringW &buf, int indent = 0)
+ {
+ for (int i = 0; i < indent; i++)
+ buf.AppendChar('\t');
+
+ wchar_t wszText[256];
+ TVITEMEX tvi = {};
+ tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_STATE;
+ tvi.hItem = hti;
+ tvi.cchTextMax = _countof(wszText);
+ tvi.pszText = wszText;
+ if (!m_tree.GetItem(&tvi)) // failure, maybe item was removed...
+ return;
+
+ buf.Append(wszText);
+ buf.Append(L"\r\n");
+
+ if (tvi.state & TVIS_EXPANDED)
+ for (hti = m_tree.GetChild(hti); hti; hti = m_tree.GetNextSibling(hti))
+ GetNodeText(hti, buf, indent + 1);
+ }
+
+ void onMenu_Tree(CContextMenuPos *pos)
+ {
+ if (!pos->hItem)
+ return;
+
+ HMENU hMenu = CreatePopupMenu();
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)1, TranslateT("Copy"));
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)2, TranslateT("Copy only this value"));
+ AppendMenu(hMenu, MF_SEPARATOR, 0, nullptr);
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel"));
+ int nReturnCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD, pos->pt.x, pos->pt.y, 0, m_hwnd, nullptr);
+ if (nReturnCmd == 1) {
+ CMStringW buf;
+ GetNodeText(pos->hItem, buf);
+ Utils_ClipboardCopy(buf);
+ }
+ else if (nReturnCmd == 2) {
+ wchar_t szBuffer[1024];
+ TVITEMEX tvi = { 0 };
+ tvi.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_STATE;
+ tvi.hItem = pos->hItem;
+ tvi.cchTextMax = _countof(szBuffer);
+ tvi.pszText = szBuffer;
+ if (m_tree.GetItem(&tvi)) {
+ if (wchar_t *str = wcsstr(szBuffer, L": "))
+ Utils_ClipboardCopy(str + 2);
+ else
+ Utils_ClipboardCopy(szBuffer);
+ }
+ }
+ DestroyMenu(hMenu);
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberUserPhotoDlgProc - Jabber photo dialog
+
+class JabberUserPhotoDlg : public JabberBaseUserInfoDlg
+{
+ HBITMAP hBitmap = nullptr;
+
+ CCtrlMButton btnSave;
+
+ UI_MESSAGE_MAP(JabberUserInfoDlg, JabberBaseUserInfoDlg);
+ UI_MESSAGE(WM_PAINT, OnPaint);
+ UI_MESSAGE_MAP_END();
+
+ char *GetFileName() const
+ {
+ ptrA jid(ppro->getUStringA(m_hContact, "jid"));
+ if (jid != nullptr) {
+ JABBER_LIST_ITEM *item = ppro->ListGetItemPtr(LIST_VCARD_TEMP, jid);
+ if (item == nullptr)
+ item = ppro->ListGetItemPtr(LIST_ROSTER, jid);
+ if (item != nullptr)
+ return item->photoFileName;
+ }
+
+ return nullptr;
+ }
+
+public:
+ JabberUserPhotoDlg(CJabberProto *_ppro) :
+ JabberBaseUserInfoDlg(_ppro, IDD_VCARD_PHOTO),
+ btnSave(this, IDC_SAVE, g_plugin.getIcon(IDI_SAVE), LPGEN("Save"))
+ {
+ btnSave.OnClick = Callback(this, &JabberUserPhotoDlg::onClick_Save);
+ }
+
+ bool OnInitDialog() override
+ {
+ ShowWindow(GetDlgItem(m_hwnd, IDC_LOAD), SW_HIDE);
+ ShowWindow(GetDlgItem(m_hwnd, IDC_DELETE), SW_HIDE);
+ return true;
+ }
+
+ void OnDestroy() override
+ {
+ if (hBitmap) {
+ ppro->debugLogA("Delete bitmap");
+ DeleteObject(hBitmap);
+ }
+ }
+
+ bool IsEmpty() const override
+ {
+ return mir_strlen(GetFileName()) == 0;
+ }
+
+ bool OnRefresh() override
+ {
+ if (hBitmap) {
+ DeleteObject(hBitmap);
+ hBitmap = nullptr;
+ }
+ btnSave.Hide();
+
+ char *pszFileName = GetFileName();
+ if (mir_strlen(pszFileName)) {
+ ppro->debugLogA("Showing picture from %s", pszFileName);
+ hBitmap = Bitmap_Load(Utf2T(pszFileName));
+ FreeImage_Premultiply(hBitmap);
+ btnSave.Show();
+ }
+
+ InvalidateRect(m_hwnd, nullptr, TRUE);
+ UpdateWindow(m_hwnd);
+ return true;
+ }
+
+ void onClick_Save(CCtrlButton *)
+ {
+ wchar_t szFilter[512];
+
+ ptrA jid(ppro->getUStringA(m_hContact, "jid"));
+ if (jid == nullptr)
+ return;
+
+ JABBER_LIST_ITEM *item = ppro->ListGetItemPtr(LIST_VCARD_TEMP, jid);
+ if (item == nullptr)
+ if ((item = ppro->ListGetItemPtr(LIST_ROSTER, jid)) == nullptr)
+ return;
+
+ switch (ProtoGetAvatarFileFormat(Utf2T(item->photoFileName))) {
+ case PA_FORMAT_BMP:
+ mir_snwprintf(szFilter, L"BMP %s (*.bmp)%c*.BMP", TranslateT("format"), 0);
+ break;
+
+ case PA_FORMAT_GIF:
+ mir_snwprintf(szFilter, L"GIF %s (*.gif)%c*.GIF", TranslateT("format"), 0);
+ break;
+
+ case PA_FORMAT_JPEG:
+ mir_snwprintf(szFilter, L"JPEG %s (*.jpg;*.jpeg)%c*.JPG;*.JPEG", TranslateT("format"), 0);
+ break;
+
+ default:
+ mir_snwprintf(szFilter, L"%s (*.*)%c*.*", TranslateT("Unknown format"), 0);
+ }
+
+ wchar_t szFileName[MAX_PATH]; szFileName[0] = '\0';
+ OPENFILENAME ofn = { 0 };
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = m_hwnd;
+ ofn.lpstrFilter = szFilter;
+ ofn.lpstrFile = szFileName;
+ ofn.nMaxFile = _MAX_PATH;
+ ofn.Flags = OFN_OVERWRITEPROMPT;
+ if (GetSaveFileName(&ofn)) {
+ ppro->debugLogW(L"File selected is %s", szFileName);
+ CopyFile(Utf2T(item->photoFileName), szFileName, FALSE);
+ }
+ }
+
+ INT_PTR OnPaint(UINT, WPARAM, LPARAM)
+ {
+ if (!ppro->m_bJabberOnline)
+ SetDlgItemText(m_hwnd, IDC_CANVAS, TranslateT("<Photo not available while offline>"));
+ else if (!hBitmap)
+ SetDlgItemText(m_hwnd, IDC_CANVAS, TranslateT("<No photo>"));
+ else {
+ BITMAP bm;
+ POINT ptSize, ptOrg, pt, ptFitSize;
+ RECT rect;
+
+ SetDlgItemTextA(m_hwnd, IDC_CANVAS, "");
+ HWND hwndCanvas = GetDlgItem(m_hwnd, IDC_CANVAS);
+ HDC hdcCanvas = GetDC(hwndCanvas);
+ HDC hdcMem = CreateCompatibleDC(hdcCanvas);
+ SelectObject(hdcMem, hBitmap);
+ SetMapMode(hdcMem, GetMapMode(hdcCanvas));
+ GetObject(hBitmap, sizeof(BITMAP), (LPVOID)&bm);
+ ptSize.x = bm.bmWidth;
+ ptSize.y = bm.bmHeight;
+ DPtoLP(hdcCanvas, &ptSize, 1);
+ ptOrg.x = ptOrg.y = 0;
+ DPtoLP(hdcMem, &ptOrg, 1);
+ GetClientRect(hwndCanvas, &rect);
+ InvalidateRect(hwndCanvas, nullptr, TRUE);
+ UpdateWindow(hwndCanvas);
+ if (ptSize.x <= rect.right && ptSize.y <= rect.bottom) {
+ pt.x = (rect.right - ptSize.x) / 2;
+ pt.y = (rect.bottom - ptSize.y) / 2;
+ ptFitSize = ptSize;
+ }
+ else {
+ if (((float)(ptSize.x - rect.right)) / ptSize.x > ((float)(ptSize.y - rect.bottom)) / ptSize.y) {
+ ptFitSize.x = rect.right;
+ ptFitSize.y = (ptSize.y * rect.right) / ptSize.x;
+ pt.x = 0;
+ pt.y = (rect.bottom - ptFitSize.y) / 2;
+ }
+ else {
+ ptFitSize.x = (ptSize.x * rect.bottom) / ptSize.y;
+ ptFitSize.y = rect.bottom;
+ pt.x = (rect.right - ptFitSize.x) / 2;
+ pt.y = 0;
+ }
+ }
+
+ RECT rc;
+ if (IsThemeActive()) {
+ GetClientRect(hwndCanvas, &rc);
+ DrawThemeParentBackground(hwndCanvas, hdcCanvas, &rc);
+ }
+ else {
+ GetClientRect(hwndCanvas, &rc);
+ FillRect(hdcCanvas, &rc, (HBRUSH)GetSysColorBrush(COLOR_BTNFACE));
+ }
+
+ if (bm.bmBitsPixel == 32) {
+ BLENDFUNCTION bf = { 0 };
+ bf.AlphaFormat = AC_SRC_ALPHA;
+ bf.BlendOp = AC_SRC_OVER;
+ bf.SourceConstantAlpha = 255;
+ GdiAlphaBlend(hdcCanvas, pt.x, pt.y, ptFitSize.x, ptFitSize.y, hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y, bf);
+ }
+ else {
+ SetStretchBltMode(hdcCanvas, COLORONCOLOR);
+ StretchBlt(hdcCanvas, pt.x, pt.y, ptFitSize.x, ptFitSize.y, hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y, SRCCOPY);
+ }
+
+ DeleteDC(hdcMem);
+ }
+ return FALSE;
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberUserPhotoDlgProc - Jabber photo dialog
+
+static int EnumOwnSessions(const char *szSetting, void *param)
+{
+ auto *pList = (LIST<char>*)param;
+
+ if (!memcmp(szSetting, omemo::DevicePrefix, sizeof(omemo::DevicePrefix)-1))
+ if (szSetting[sizeof(omemo::DevicePrefix)] != 0)
+ pList->insert(mir_strdup(szSetting));
+
+ return 0;
+}
+
+static int EnumOmemoSessions(const char *szSetting, void *param)
+{
+ auto *pList = (LIST<char>*)param;
+
+ if (!memcmp(szSetting, omemo::IdentityPrefix, sizeof(omemo::IdentityPrefix) - 1))
+ pList->insert(mir_strdup(szSetting + sizeof(omemo::IdentityPrefix)));
+
+ return 0;
+}
+
+class JabberUserOmemoDlg : public JabberBaseUserInfoDlg
+{
+ CCtrlListView m_list;
+
+ void AddListItem(const CMStringA &pszStr1, const wchar_t *pszStr2, const CMStringA &pszStr3)
+ {
+ LVITEM lvi = {};
+ lvi.mask = LVIF_TEXT;
+ lvi.pszText = mir_a2u(pszStr1);
+ lvi.iItem = 100500;
+ int idx = m_list.InsertItem(&lvi);
+ mir_free(lvi.pszText);
+
+ m_list.SetItemText(idx, 1, (wchar_t *)pszStr2);
+ CMStringW fp = omemo::FormatFingerprint(pszStr3);
+ m_list.SetItemText(idx, 2, fp.GetBuffer());
+ }
+
+public:
+ JabberUserOmemoDlg(CJabberProto *_ppro) :
+ JabberBaseUserInfoDlg(_ppro, IDD_INFO_OMEMO),
+ m_list(this, IDC_LIST)
+ {
+ }
+
+ bool OnInitDialog() override
+ {
+ LV_COLUMN lvc = {};
+ lvc.mask = LVCF_TEXT | LVCF_WIDTH;
+
+ lvc.cx = 90;
+ lvc.pszText = TranslateT("Device ID");
+ m_list.InsertColumn(1, &lvc);
+
+ lvc.cx = 80;
+ lvc.pszText = TranslateT("Status");
+ m_list.InsertColumn(2, &lvc);
+
+ lvc.cx = 550;
+ lvc.pszText = TranslateT("Fingerprint");
+ m_list.InsertColumn(3, &lvc);
+
+ if (m_hContact == 0)
+ OnRefresh();
+ return true;
+ }
+
+ int Resizer(UTILRESIZECONTROL*) override
+ {
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
+ }
+
+ bool OnRefresh() override
+ {
+ m_list.DeleteAllItems();
+
+ if (m_hContact == 0) {
+ // GetOwnDeviceId() creates own keys if they don't exist
+ CMStringA str1(FORMAT, "%d", ppro->m_omemo.GetOwnDeviceId());
+ CMStringA str2(ppro->getMStringA("OmemoFingerprintOwn"));
+ AddListItem(str1, TranslateT("Own device"), str2);
+ }
+
+ for (int i = 0;; i++) {
+ CMStringA szSetting(FORMAT, "%s%d", omemo::DevicePrefix, i);
+ uint32_t device_id = ppro->getDword(m_hContact, szSetting, 0);
+ if (device_id == 0)
+ break;
+
+ char *jiddev = ppro->getStringA(m_hContact, "jid");
+ if (jiddev == 0)
+ continue;
+
+ size_t len = strlen(jiddev);
+ jiddev = (char *)mir_realloc(jiddev, len + sizeof(int32_t));
+ memcpy(jiddev + len, &device_id, sizeof(int32_t));
+
+ szSetting = omemo::IdentityPrefix;
+ szSetting.Append(ptrA(mir_base64_encode(jiddev, len + sizeof(int32_t))));
+ mir_free(jiddev);
+
+ const wchar_t *pwszStatus = L"";
+ CMStringA fp_hex;
+ DBVARIANT dbv = { 0 };
+ dbv.type = DBVT_BLOB;
+ db_get(m_hContact, ppro->m_szModuleName, szSetting, &dbv);
+ if (dbv.cpbVal == 33) {
+ fp_hex.Truncate(33 * 2);
+ bin2hex(dbv.pbVal, 33, fp_hex.GetBuffer());
+ uint8_t trusted = ppro->getByte(m_hContact, "OmemoFingerprintTrusted_" + fp_hex);
+ pwszStatus = trusted ? TranslateT("Trusted") : TranslateT("UNTRUSTED");
+ //TODO: 3 states Trusted, Untrusted, TOFU
+ }
+ else if (dbv.cpbVal)
+ pwszStatus = TranslateT("Unknown");
+
+ db_free(&dbv);
+
+ AddListItem(CMStringA(FORMAT, "%d", device_id), pwszStatus, fp_hex);
+ }
+ return false;
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// OnInfoInit - initializes user info option dialogs
+
+int CJabberProto::OnUserInfoInit(WPARAM wParam, LPARAM hContact)
+{
+ if (!Proto_GetAccount(m_szModuleName))
+ return 0;
+
+ if (hContact == 0) {
+ // Show our vcard
+ OnUserInfoInit_VCard(wParam, hContact);
+ return 0;
+ }
+
+ char *szProto = Proto_GetBaseAccountName(hContact);
+ if (szProto != nullptr && !mir_strcmp(szProto, m_szModuleName)) {
+ USERINFOPAGE uip = {};
+ uip.dwInitParam = (LPARAM)this;
+ uip.flags = ODPF_UNICODE | ODPF_USERINFOTAB | ODPF_ICON;
+ uip.szGroup.w = m_tszUserName;
+ uip.dwInitParam = (LPARAM)Skin_GetProtoIcon(m_szModuleName, ID_STATUS_ONLINE);
+
+ uip.pDialog = new JabberUserInfoDlg(this);
+ uip.position = -2000000000;
+ uip.szTitle.w = LPGENW("Account");
+ g_plugin.addUserInfo(wParam, &uip);
+
+ uip.pDialog = new JabberUserPhotoDlg(this);
+ uip.position = 2000000000;
+ uip.szTitle.w = LPGENW("Photo");
+ g_plugin.addUserInfo(wParam, &uip);
+
+ CheckOmemoUserInfo(wParam, uip);
+ }
+
+ return 0;
+}
+
+void CJabberProto::CheckOmemoUserInfo(WPARAM wParam, USERINFOPAGE &uip)
+{
+ if (m_bUseOMEMO) {
+ uip.pDialog = new JabberUserOmemoDlg(this);
+ uip.position = 2000000001;
+ uip.szTitle.w = L"OMEMO";
+ g_plugin.addUserInfo(wParam, &uip);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberUserInfoUpdate
+
+void JabberUserInfoInit()
+{
+ hUserInfoList = WindowList_Create();
+}
+
+void JabberUserInfoUninit()
+{
+ WindowList_Destroy(hUserInfoList);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberUserInfoUpdate
+
+void JabberUserInfoUpdate(MCONTACT hContact)
+{
+ if (!hContact)
+ WindowList_BroadcastAsync(hUserInfoList, WM_PROTO_REFRESH, 0, 0);
+ else if (HWND hwnd = WindowList_Find(hUserInfoList, hContact))
+ PostMessage(hwnd, WM_PROTO_REFRESH, 0, 0);
+}
diff --git a/protocols/JabberG/src/jabber_util.cpp b/protocols/JabberG/src/jabber_util.cpp
index 3eebd4e2c7..a3e1c856f6 100644
--- a/protocols/JabberG/src/jabber_util.cpp
+++ b/protocols/JabberG/src/jabber_util.cpp
@@ -4,7 +4,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_vcard.cpp b/protocols/JabberG/src/jabber_vcard.cpp
index 0d722aac37..aad0f8d9be 100644
--- a/protocols/JabberG/src/jabber_vcard.cpp
+++ b/protocols/JabberG/src/jabber_vcard.cpp
@@ -4,7 +4,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_xml.cpp b/protocols/JabberG/src/jabber_xml.cpp
index b53ca07d45..c3a166017a 100644
--- a/protocols/JabberG/src/jabber_xml.cpp
+++ b/protocols/JabberG/src/jabber_xml.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_xml.h b/protocols/JabberG/src/jabber_xml.h
index 16f2626b1c..4ecdde53ea 100644
--- a/protocols/JabberG/src/jabber_xml.h
+++ b/protocols/JabberG/src/jabber_xml.h
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_xstatus.cpp b/protocols/JabberG/src/jabber_xstatus.cpp
index b67347f7e7..0a989d9dd6 100644
--- a/protocols/JabberG/src/jabber_xstatus.cpp
+++ b/protocols/JabberG/src/jabber_xstatus.cpp
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_xstatus.h b/protocols/JabberG/src/jabber_xstatus.h
index 0d2bbb266a..80358daca6 100644
--- a/protocols/JabberG/src/jabber_xstatus.h
+++ b/protocols/JabberG/src/jabber_xstatus.h
@@ -6,7 +6,7 @@ Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007-09 Maxim Mluhov
Copyright (c) 2007-09 Victor Pavlychko
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/jabber_zstream.cpp b/protocols/JabberG/src/jabber_zstream.cpp
index 0931e4fc34..87f21d44aa 100644
--- a/protocols/JabberG/src/jabber_zstream.cpp
+++ b/protocols/JabberG/src/jabber_zstream.cpp
@@ -6,7 +6,7 @@ XEP-0138 (Stream Compression) implementation
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Kostya Chukavin, Taras Zackrepa
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/stdafx.cxx b/protocols/JabberG/src/stdafx.cxx
index f64d25234b..ebbde0ade1 100644
--- a/protocols/JabberG/src/stdafx.cxx
+++ b/protocols/JabberG/src/stdafx.cxx
@@ -1,5 +1,5 @@
/*
-Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org)
+Copyright (C) 2012-23 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
diff --git a/protocols/JabberG/src/stdafx.h b/protocols/JabberG/src/stdafx.h
index da81c661c9..d848e5a215 100644
--- a/protocols/JabberG/src/stdafx.h
+++ b/protocols/JabberG/src/stdafx.h
@@ -5,7 +5,7 @@ Jabber Protocol Plugin for Miranda NG
Copyright (c) 2002-04 Santithorn Bunchua
Copyright (c) 2005-12 George Hazan
Copyright (c) 2007 Maxim Mluhov
-Copyright (C) 2012-22 Miranda NG team
+Copyright (C) 2012-23 Miranda NG team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
diff --git a/protocols/JabberG/src/version.h b/protocols/JabberG/src/version.h
index 29a9e971eb..1308d51095 100644
--- a/protocols/JabberG/src/version.h
+++ b/protocols/JabberG/src/version.h
@@ -9,5 +9,5 @@
#define __FILENAME "Jabber.dll"
#define __DESCRIPTION "Jabber (XMPP) protocol support for Miranda NG."
#define __AUTHOR "George Hazan, Maxim Mluhov, Victor Pavlychko, Artem Shpynov, Michael Stepura"
-#define __COPYRIGHT "© 2005-22 George Hazan, Maxim Mluhov, Victor Pavlychko, Artem Shpynov, Michael Stepura"
+#define __COPYRIGHT "© 2005-23 George Hazan, Maxim Mluhov, Victor Pavlychko, Artem Shpynov, Michael Stepura"
#define __AUTHORWEB "https://miranda-ng.org/p/Jabber"