22//
33// SPDX-License-Identifier: GPL-3.0-or-later
44
5+ #include < QCoreApplication>
56#include < QDateTime>
7+ #include < QDBusConnectionInterface>
68#include < QDBusInterface>
79#include < QDBusPendingReply>
10+ #include < QDBusServiceWatcher>
811#include < QNetworkInterface>
12+ #include < QTranslator>
13+ #include < QLocale>
14+ #include < QLibraryInfo>
15+ #include < DConfig>
916
1017#include < unistd.h>
1118
12- #include " utils.h"
1319#include " loginreminderinfo.h"
1420
21+ DCORE_USE_NAMESPACE
22+
23+ // 前置声明
24+ int checkPasswordExpired ();
1525
1626int start ()
1727{
1828 qDebug () << " login reminder init" ;
19- #if 0
20- // TODO has no 'com.deepin.dde.startdde' gsetting
21- if (!Utils::SettingValue("com.deepin.dde.startdde", QByteArray(), "login-reminder", false).toBool())
22- return 0;
23- #endif
24- // 登录后展示横幅通知信息
29+
30+ // 读取 DConfig 配置,检查 LoginReminder 是否开启
31+ DConfig *config = DConfig::create (" org.deepin.dde.session" , " org.deepin.dde.session" );
32+ bool loginReminderEnabled = false ; // 默认关闭
33+ if (config && config->isValid ()) {
34+ loginReminderEnabled = config->value (" LoginReminder" , false ).toBool ();
35+ qDebug () << " LoginReminder enabled:" << loginReminderEnabled;
36+ }
37+
38+ // 如果 login-reminder 没有开启,仅检查密码过期情况
39+ if (!loginReminderEnabled) {
40+ qDebug () << " LoginReminder is disabled, only checking password expiration" ;
41+ return checkPasswordExpired ();
42+ }
43+
2544 QDBusInterface userInter (" org.deepin.dde.Accounts1" , QString (" /org/deepin/dde/Accounts1/User%1" ).arg (getuid ()), " org.deepin.dde.Accounts1.User" , QDBusConnection::systemBus ());
2645 QDBusPendingReply<LoginReminderInfo> reply = userInter.call (" GetReminderInfo" );
2746 if (reply.isError ()) {
@@ -69,11 +88,18 @@ int start()
6988 const QString &address = (info.CurrentLogin .Address == " 0.0.0.0" ) ? getFirstIpAddress () : info.CurrentLogin .Address ;
7089 QString body = QString (" %1 %2 %3" ).arg (info.Username ).arg (address).arg (currentLoginTime);
7190 int daysLeft = info.spent .LastChange + info.spent .Max - int (QDateTime::currentSecsSinceEpoch () / SECONDS_PER_DAY);
91+ bool needNotify = false ;
7292 if ((info.spent .Max != -1 ) && (info.spent .Warn != -1 ) && (info.spent .Warn > daysLeft)) {
93+ needNotify = true ;
7394 body += " " + QString (QObject::tr (" Your password will expire in %1 days" )).arg (daysLeft);
7495 }
75- body += " \n " + QString (QObject::tr (" %1 login failures since the last successful login" )).arg (info.FailCountSinceLastLogin );
76-
96+ if (info.FailCountSinceLastLogin > 0 ) {
97+ needNotify = true ;
98+ body += " \n " + QString (QObject::tr (" %1 login failures since the last successful login" )).arg (info.FailCountSinceLastLogin );
99+ }
100+ if (!needNotify) {
101+ return 0 ;
102+ }
77103 const QString &lastLoginTime = info.LastLogin .Time .left (QString (" yyyy-MM-dd hh:mm:ss" ).length ());
78104 QString content;
79105 content += QString (" <p>%1</p>" ).arg (info.Username );
@@ -95,7 +121,7 @@ int start()
95121 uint notifyId = notifyIdReply.value ();
96122
97123 // 5秒后自动关闭通知,避免在通知中心中显示
98- sleep (5 );
124+ sleep (10 );
99125
100126 QDBusPendingReply<> closeReply = notifyInter->call (" CloseNotification" , notifyId);
101127 if (closeReply.isError ()) {
@@ -107,13 +133,154 @@ int start()
107133 return 0 ;
108134}
109135
136+ int checkPasswordExpired () {
137+ qDebug () << " check password expired" ;
138+
139+ // 调用 PasswordExpiredInfo 获取密码过期信息
140+ QDBusInterface userInter (" org.deepin.dde.Accounts1" ,
141+ QString (" /org/deepin/dde/Accounts1/User%1" ).arg (getuid ()),
142+ " org.deepin.dde.Accounts1.User" ,
143+ QDBusConnection::systemBus ());
144+
145+ QDBusMessage reply = userInter.call (" PasswordExpiredInfo" );
146+ if (reply.type () == QDBusMessage::ErrorMessage) {
147+ qWarning () << " failed to retrieve password expired info, error: " << reply.errorMessage ();
148+ return -1 ;
149+ }
150+
151+ // 解析返回值: (Int32 expiredStatus, Int64 dayLeft)
152+ QList<QVariant> args = reply.arguments ();
153+ if (args.size () < 2 ) {
154+ qWarning () << " invalid reply from PasswordExpiredInfo" ;
155+ return -1 ;
156+ }
157+
158+ int expiredStatus = args[0 ].toInt ();
159+ qint64 dayLeft = args[1 ].toLongLong ();
160+
161+ qDebug () << " Password expired status:" << expiredStatus << " , days left:" << dayLeft;
162+
163+ // expiredStatus: 0=正常, 1=即将过期, 2=已过期
164+ if (expiredStatus == 0 ) {
165+ qDebug () << " Password is valid, no notification needed" ;
166+ return 0 ;
167+ }
168+
169+ // 构建通知内容
170+ QString title = QObject::tr (" Password Expiration Warning" );
171+ QString body;
172+ QString content;
173+
174+ if (expiredStatus == 2 ) {
175+ // 密码已过期
176+ body = QObject::tr (" Your password has expired. Please change it immediately." );
177+ content = QString (" <p><b>%1</b></p>" ).arg (QObject::tr (" Your password has expired!" ));
178+ content += QString (" <p>%1</p>" ).arg (QObject::tr (" For security reasons, please change your password immediately." ));
179+ } else if (expiredStatus == 1 && dayLeft > 0 ) {
180+ // 密码即将过期
181+ body = QObject::tr (" Your password will expire in %1 days. Please change it soon." ).arg (dayLeft);
182+ content = QString (" <p><b>%1</b></p>" ).arg (QObject::tr (" Password Expiration Warning" ));
183+ content += QString (" <p>%1</p>" ).arg (QObject::tr (" Your password will expire in %1 days." ).arg (dayLeft));
184+ content += QString (" <p>%1</p>" ).arg (QObject::tr (" Please change your password as soon as possible." ));
185+ } else {
186+ // 其他情况
187+ qDebug () << " Unknown password status, no notification" ;
188+ return 0 ;
189+ }
190+
191+ // 发送通知
192+ QDBusInterface *notifyInter = new QDBusInterface (" org.freedesktop.Notifications" ,
193+ " /org/freedesktop/Notifications" ,
194+ " org.freedesktop.Notifications" );
195+ QVariantMap hints;
196+ // 点击通知后打开控制中心的账户密码修改页面
197+ hints.insert (QString (" x-deepin-action-change_password" ),
198+ QVariant (QString (" dbus-send,--print-reply,--dest=org.deepin.dde.ControlCenter1,/org/deepin/dde/ControlCenter1,org.deepin.dde.ControlCenter1.ShowPage,string:accountsloginMethodItempassword" )));
199+
200+ QDBusPendingReply<uint> notifyIdReply = notifyInter->call (" Notify" ,
201+ " dde-control-center" ,
202+ uint (0 ),
203+ " preferences-system" ,
204+ title,
205+ body,
206+ QStringList () << " change_password" << QObject::tr (" Change Password" ),
207+ hints,
208+ int (0 ));
209+ if (notifyIdReply.isError ()) {
210+ qWarning () << " failed to call notification, error: " << notifyIdReply.error ().message ();
211+ return -1 ;
212+ }
213+ uint notifyId = notifyIdReply.value ();
214+
215+ // 10秒后自动关闭通知
216+ sleep (5 );
217+
218+ QDBusPendingReply<> closeReply = notifyInter->call (" CloseNotification" , notifyId);
219+ if (closeReply.isError ()) {
220+ qWarning () << " failed to close notification, error: " << closeReply.error ().message ();
221+ return -1 ;
222+ }
223+
224+ qDebug () << " password expired check finished" ;
225+ return 0 ;
226+ }
227+
110228int main (int argc, char *argv[])
111229{
112- Q_UNUSED (argc);
113- Q_UNUSED (argv);
230+ QCoreApplication app (argc, argv);
231+ app.setOrganizationName (" deepin" );
232+ app.setApplicationName (" dde-login-reminder" );
233+
234+ // 加载翻译文件
235+ QTranslator *translator = new QTranslator (&app);
236+ QString locale = QLocale::system ().name ();
237+
238+ // 尝试多个可能的翻译路径
239+ QStringList translationPaths;
240+ translationPaths << QString (CMAKE_INSTALL_FULL_DATADIR) + " /dde-login-reminder/translations"
241+ << " /usr/share/dde-login-reminder/translations"
242+ << " /usr/local/share/dde-login-reminder/translations" ;
243+
244+ bool loaded = false ;
245+ for (const QString &path : translationPaths) {
246+ if (translator->load (QString (" dde-login-reminder_%1" ).arg (locale), path)) {
247+ app.installTranslator (translator);
248+ qDebug () << " Loaded translation for locale:" << locale << " from" << path;
249+ loaded = true ;
250+ break ;
251+ }
252+ }
253+
254+ if (!loaded) {
255+ qDebug () << " Failed to load translation for locale:" << locale;
256+ qDebug () << " Tried paths:" << translationPaths;
257+ }
114258
115259 registerLoginReminderInfoMetaType ();
116260
117- return 0 ;
118- // return start();
119- }
261+ // 检查 org.deepin.dde.Notification1 服务是否已启动
262+ QDBusConnectionInterface *interface = QDBusConnection::sessionBus ().interface ();
263+ if (interface->isServiceRegistered (" org.deepin.dde.Notification1" )) {
264+ // 服务已启动,直接执行
265+ qDebug () << " Notification service already available, starting immediately" ;
266+ int result = start ();
267+ return result;
268+ }
269+
270+ // 服务未启动,动态监听服务注册
271+ qDebug () << " Notification service not available, waiting for it to start..." ;
272+ QDBusServiceWatcher *watcher = new QDBusServiceWatcher (
273+ " org.deepin.dde.Notification1" ,
274+ QDBusConnection::sessionBus (),
275+ QDBusServiceWatcher::WatchForRegistration,
276+ &app
277+ );
278+
279+ QObject::connect (watcher, &QDBusServiceWatcher::serviceRegistered, [&app](const QString &serviceName) {
280+ qDebug () << " Notification service registered:" << serviceName;
281+ int result = start ();
282+ app.exit (result);
283+ });
284+
285+ return app.exec ();
286+ }
0 commit comments