1 #include "config.h"
2
3 #ifdef CONFIG_SESSION
4
5 #include "ysmapp.h"
6 #include "sysdep.h"
7 #include "base.h"
8 #include "yconfig.h"
9
10 #include "intl.h"
11
12 #include <X11/SM/SMlib.h>
13
14 YSMApplication *smapp = nullptr;
15 static int IceSMfd = -1;
16 static IceConn IceSMconn = nullptr;
17 static SmcConn SMconn = nullptr;
18 static char *oldSessionId = nullptr;
19 static char *newSessionId = nullptr;
20 static char *sessionProg;
21
getsesfile()22 upath getsesfile() {
23 upath path(YApplication::getPrivConfDir());
24 if (false == path.dirExists())
25 path.mkdir();
26 path += mstring("/.session-", newSessionId);
27 return path;
28 }
29
iceWatchFD(IceConn conn,IcePointer,Bool opening,IcePointer *)30 static void iceWatchFD(IceConn conn,
31 IcePointer /*client_data*/,
32 Bool opening,
33 IcePointer* /*watch_data*/)
34 {
35 if (opening) {
36 if (IceSMfd != -1) { // shouldn't happen
37 warn("TOO MANY ICE CONNECTIONS -- not supported");
38 } else {
39 IceSMfd = IceConnectionNumber(conn);
40 fcntl(IceSMfd, F_SETFD, FD_CLOEXEC);
41 }
42 } else {
43 if (IceConnectionNumber(conn) == IceSMfd)
44 IceSMfd = -1;
45 }
46 }
47
saveYourselfPhase2Proc(SmcConn,SmPointer)48 static void saveYourselfPhase2Proc(SmcConn /*conn*/, SmPointer /*client_data*/) {
49 smapp->smSaveYourselfPhase2();
50 }
51
saveYourselfProc(SmcConn,SmPointer,int,Bool shutdown,int,Bool fast)52 static void saveYourselfProc(SmcConn /*conn*/,
53 SmPointer /*client_data*/,
54 int /*save_type*/,
55 Bool shutdown,
56 int /*interact_style*/,
57 Bool fast)
58 {
59 smapp->smSaveYourself(shutdown ? true : false, fast ? true : false);
60 }
61
shutdownCancelledProc(SmcConn,SmPointer)62 static void shutdownCancelledProc(SmcConn /*conn*/, SmPointer /*client_data*/) {
63 smapp->smShutdownCancelled();
64 }
65
saveCompleteProc(SmcConn,SmPointer)66 static void saveCompleteProc(SmcConn /*conn*/, SmPointer /*client_data*/) {
67 smapp->smSaveComplete();
68 }
69
dieProc(SmcConn,SmPointer)70 static void dieProc(SmcConn /*conn*/, SmPointer /*client_data*/) {
71 smapp->smDie();
72 }
73
setSMProperties()74 static void setSMProperties() {
75 SmPropValue programVal = { 0, nullptr };
76 SmPropValue userIDVal = { 0, nullptr };
77 SmPropValue restartVal[3] = { { 0, nullptr }, { 0, nullptr }, { 0, nullptr } };
78 SmPropValue discardVal[4] = { { 0, nullptr }, { 0, nullptr }, { 0, nullptr } };
79
80 // broken headers in SMlib?
81 SmProp programProp = { (char *)SmProgram, (char *)SmLISTofARRAY8, 1, &programVal };
82 SmProp userIDProp = { (char *)SmUserID, (char *)SmARRAY8, 1, &userIDVal };
83 SmProp restartProp = { (char *)SmRestartCommand, (char *)SmLISTofARRAY8, 3, (SmPropValue *)&restartVal };
84 SmProp cloneProp = { (char *)SmCloneCommand, (char *)SmLISTofARRAY8, 1, (SmPropValue *)&restartVal };
85 SmProp discardProp = { (char *)SmDiscardCommand, (char *)SmLISTofARRAY8, 3, (SmPropValue *)&discardVal };
86 SmProp *props[] = {
87 &programProp,
88 &userIDProp,
89 &restartProp,
90 &cloneProp,
91 &discardProp
92 };
93
94 char *user = getenv("USER");
95 if (!user) // not a user?
96 user = getenv("LOGNAME");
97 if (!user) {
98 msg(_("$USER or $LOGNAME not set?"));
99 return ;
100 }
101 const char *clientId = "--client-id";
102
103 programVal.length = strlen(sessionProg);
104 programVal.value = sessionProg;
105 userIDVal.length = strlen(user);
106 userIDVal.value = (SmPointer)user;
107
108 restartVal[0].length = strlen(sessionProg);
109 restartVal[0].value = sessionProg;
110 restartVal[1].length = strlen(clientId);
111 restartVal[1].value = (char *)clientId;
112 restartVal[2].length = strlen(newSessionId);
113 restartVal[2].value = newSessionId;
114
115 const char *rmprog = "/bin/rm";
116 const char *rmarg = "-f";
117 upath sidfile = getsesfile();
118
119 discardVal[0].length = strlen(rmprog);
120 discardVal[0].value = (char *)rmprog;
121 discardVal[1].length = strlen(rmarg);
122 discardVal[1].value = (char *)rmarg;
123 discardVal[2].length = sidfile.length();
124 discardVal[2].value = (char *)sidfile.string();
125
126 SmcSetProperties(SMconn,
127 (int) ACOUNT(props),
128 (SmProp **)&props);
129 }
130
initSM()131 static void initSM() {
132 if (getenv("SESSION_MANAGER") == nullptr)
133 return;
134 if (IceAddConnectionWatch(&iceWatchFD, nullptr) == 0) {
135 warn("Session Manager: IceAddConnectionWatch failed.");
136 return ;
137 }
138
139 char error_str[256];
140 SmcCallbacks smcall;
141
142 memset(&smcall, 0, sizeof(smcall));
143 smcall.save_yourself.callback = &saveYourselfProc;
144 smcall.save_yourself.client_data = nullptr;
145 smcall.die.callback = &dieProc;
146 smcall.die.client_data = nullptr;
147 smcall.save_complete.callback = &saveCompleteProc;
148 smcall.save_complete.client_data = nullptr;
149 smcall.shutdown_cancelled.callback = &shutdownCancelledProc;
150 smcall.shutdown_cancelled.client_data = nullptr;
151
152 if ((SMconn = SmcOpenConnection(nullptr, /* network ids */
153 nullptr, /* context */
154 1, 0, /* protocol major, minor */
155 SmcSaveYourselfProcMask |
156 SmcSaveCompleteProcMask |
157 SmcShutdownCancelledProcMask |
158 SmcDieProcMask,
159 &smcall,
160 oldSessionId, &newSessionId,
161 sizeof(error_str), error_str)) == nullptr)
162 {
163 warn("Session Manager: Init error: %s", error_str);
164 return ;
165 }
166 IceSMconn = SmcGetIceConnection(SMconn);
167
168 setSMProperties();
169 }
170
smSaveYourself(bool,bool)171 void YSMApplication::smSaveYourself(bool /*shutdown*/, bool /*fast*/) {
172 SmcRequestSaveYourselfPhase2(SMconn, &saveYourselfPhase2Proc, nullptr);
173 }
174
smSaveYourselfPhase2()175 void YSMApplication::smSaveYourselfPhase2() {
176 SmcSaveYourselfDone(SMconn, True);
177 }
178
smSaveDone()179 void YSMApplication::smSaveDone() {
180 SmcSaveYourselfDone(SMconn, True);
181 }
182
smSaveComplete()183 void YSMApplication::smSaveComplete() {
184 }
185
smShutdownCancelled()186 void YSMApplication::smShutdownCancelled() {
187 SmcSaveYourselfDone(SMconn, False);
188 }
189
smCancelShutdown()190 void YSMApplication::smCancelShutdown() {
191 SmcSaveYourselfDone(SMconn, False); /// !!! broken
192 }
193
smDie()194 void YSMApplication::smDie() {
195 this->exit(0);
196 }
197
haveSessionManager()198 bool YSMApplication::haveSessionManager() {
199 if (SMconn != nullptr)
200 return true;
201 return false;
202 }
203
smRequestShutdown()204 void YSMApplication::smRequestShutdown() {
205 // !!! doesn't seem to work with xsm
206 SmcRequestSaveYourself(SMconn,
207 SmSaveLocal, //!!!
208 True,
209 SmInteractStyleAny,
210 False,
211 True);
212 }
213
YSMApplication(int * argc,char *** argv,const char * displayName)214 YSMApplication::YSMApplication(int *argc, char ***argv, const char *displayName):
215 YXApplication(argc, argv, displayName)
216 {
217 smapp = this;
218 for (char ** arg = *argv + 1; arg < *argv + *argc; ++arg) {
219 if (**arg == '-') {
220 char *value;
221 if (GetLongArgument(value, "client-id", arg, *argv+*argc))
222 {
223 oldSessionId = value;
224 continue;
225 }
226 }
227 }
228
229 sessionProg = (*argv)[0]; //ICEWMEXE;
230 initSM();
231 psm.registerPoll(IceSMfd);
232 }
233
~YSMApplication()234 YSMApplication::~YSMApplication() {
235 if (SMconn != nullptr) {
236 SmcCloseConnection(SMconn, 0, nullptr);
237 SMconn = nullptr;
238 IceSMconn = nullptr;
239 IceSMfd = -1;
240 unregisterPoll(&psm);
241 }
242 }
243
notifyRead()244 void YSMPoll::notifyRead() {
245 Bool rep;
246 if (IceProcessMessages(IceSMconn, nullptr, &rep)
247 == IceProcessMessagesIOError)
248 {
249 SmcCloseConnection(SMconn, 0, nullptr);
250 IceSMconn = nullptr;
251 IceSMfd = -1;
252 unregisterPoll();
253 }
254 }
255
256 #endif /* CONFIG_SESSION */
257
258 // vim: set sw=4 ts=4 et:
259