c88d3a90de9d97de737b88731394a06aea28451a
[citadel.git] / webcit / who.c
1 /*
2  * $Id$
3  */
4 /**
5  * \defgroup DislpayWho Display a list of all users currently logged on to the Citadel server.
6  * \ingroup WebcitDisplayItems
7  */
8 /*@{*/
9 #include "webcit.h"
10
11
12 typedef struct UserStateStruct {
13         char *UserName;
14         long UserNameLen;
15         char *Room;
16         long RoomLen;
17         char *Host;
18         long HostLen;
19         char *RealRoom;
20         long RealRoomLen;
21         char *RealHost;
22         long RealHostLen;
23         long LastActive;
24         int Session;
25         int Idle;
26         int SessionCount;
27 } UserStateStruct;
28
29 void DestroyUserStruct(void *vUser)
30 {
31         UserStateStruct *User = (UserStateStruct*) vUser;
32         free(User->UserName);
33         free(User->Room);
34         free(User->Host);
35         free(User->RealRoom);
36         free(User->RealHost);
37         free(User);
38 }
39
40 int CompareUserStruct(const void *VUser1, const void *VUser2)
41 {
42         const UserStateStruct *User1 = (UserStateStruct*) GetSearchPayload(VUser1);
43         const UserStateStruct *User2 = (UserStateStruct*) GetSearchPayload(VUser2);
44         
45         if (User1->Idle != User2->Idle)
46                 return User1->Idle > User2->Idle;
47         return strcasecmp(User1->UserName, User2->UserName);
48 }
49
50
51 int GetWholistSection(HashList *List, time_t now)
52 {
53         struct wcsession *WCC = WC;     /* This is done to make it run faster; WC is a function */
54         UserStateStruct *User, *OldUser;
55         void *VOldUser;
56         char buf[SIZ], user[SIZ], room[SIZ], host[SIZ],
57                 realroom[SIZ], realhost[SIZ];
58         size_t BufLen;
59
60         serv_puts("RWHO");
61         serv_getln(buf, sizeof buf);
62         if (buf[0] == '1') {
63                 while (BufLen = serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
64                         if (BufLen <= 0)
65                             continue;
66                         User = (UserStateStruct*) malloc(sizeof(UserStateStruct));
67                         User->Session = extract_int(buf, 0);
68
69                         User->UserNameLen = extract_token(user, buf, 1, '|', sizeof user);
70                         User->UserName = malloc(User->UserNameLen + 1);
71                         memcpy(User->UserName, user, User->UserNameLen + 1);
72
73                         User->RoomLen = extract_token(room, buf, 2, '|', sizeof room);
74                         User->Room = malloc(User->RoomLen + 1);
75                         memcpy(User->Room, room, User->RoomLen + 1);
76
77                         User->HostLen = extract_token(host, buf, 3, '|', sizeof host);
78                         User->Host = malloc(User->HostLen + 1);
79                         memcpy(User->Host, host, User->HostLen + 1);
80
81                         User->RealRoomLen = extract_token(realroom, buf, 9, '|', sizeof realroom);
82                         User->RealRoom = malloc(User->RealRoomLen + 1);
83                         memcpy(User->RealRoom, realroom, User->RealRoomLen + 1);
84
85                         User->RealHostLen = extract_token(realhost, buf, 10, '|', sizeof realhost);
86                         User->RealHost = malloc(User->RealHostLen + 1);
87                         memcpy(User->RealHost, realhost, User->RealHostLen + 1);
88                         
89                         User->LastActive = extract_long(buf, 5);
90                         User->Idle = (now - User->LastActive) > 900L;
91                         User->SessionCount = 1;
92
93                         if (GetHash(List, User->UserName, User->UserNameLen, &VOldUser)) {
94                                 OldUser = VOldUser;
95                                 OldUser->SessionCount++;
96                                 if (!User->Idle) {
97                                         if (User->Session == WCC->ctdl_pid) 
98                                                 OldUser->Session = User->Session;
99
100                                         OldUser->Idle = User->Idle;
101                                         OldUser->LastActive = User->LastActive;
102                                 }
103                                 DestroyUserStruct(User);
104                         }
105                         else
106                                 Put(List, User->UserName, User->UserNameLen, User, DestroyUserStruct);
107                 }
108                 SortByPayload(List, CompareUserStruct);
109                 return 1;
110         }
111         else
112                 return 0;
113 }
114
115 /**
116  * \brief Display inner div of Wholist
117  */
118 void who_inner_div(void) {
119         UserStateStruct *User;
120         void *VUser;
121         char buf[SIZ];
122         struct wcsession *WCC = WC;     /* This is done to make it run faster; WC is a function */
123         HashList *List;
124         HashPos  *it;
125         char *UserName;
126         long len;
127         time_t now;
128         int bg = 0;
129
130         wprintf("<table class=\"altern\">"
131                 "<tr>\n");
132         wprintf("<th class=\"edit_col\"> </th>\n");
133         wprintf("<th colspan=\"2\"> </th>\n");
134         wprintf("<th>%s</th>\n", _("User name"));
135         wprintf("<th>%s</th>", _("Room"));
136         wprintf("<th class=\"host_col\">%s</th>\n</tr>\n", _("From host"));
137
138         serv_puts("TIME");
139         serv_getln(buf, sizeof buf);
140
141         if (buf[0] == '2') {
142                 now = extract_long(&buf[4], 0);
143         }
144         else {
145                 now = time(NULL);
146         }
147
148         List = NewHash();
149
150         if (GetWholistSection(List, now)) {
151                 it = GetNewHashPos();
152                 while (GetNextHashPos(List, it, &len, &UserName, &VUser)) {
153                         User = VUser;
154                         bg = 1 - bg;
155                         wprintf("<tr class=\"%s\">",
156                                 (bg ? "even" : "odd")
157                         );
158
159
160                         wprintf("<td class=\"edit_col\">");
161                         if ((WCC->is_aide) &&
162                             (User->Session != WCC->ctdl_pid)) {
163                                 wprintf(" <a href=\"terminate_session?which_session=%d", User->Session);
164                                 wprintf("\" onClick=\"return ConfirmKill();\">%s</a>", _("(kill)"));
165                         }
166                         if (User->Session == WCC->ctdl_pid) {
167                                 wprintf(" <a href=\"edit_me\">%s</a>", _("(edit)"));
168                         }
169                         wprintf("</td>");
170
171                         /** (link to page this user) */
172                         wprintf("<td width=\"5%\"><a href=\"display_page?recp=");
173                         urlescputs(User->UserName);
174                         wprintf("\">"
175                                 "<img align=\"middle\" "
176                                 "src=\"static/citadelchat_24x.gif\" "
177                                 "alt=\"(p)\""
178                                 " border=\"0\" /></a> ");
179                         wprintf("</td>");
180
181                         /** (idle flag) */
182                         wprintf("<td width=\"5%\">");
183                         if (User->Idle) {
184                                 wprintf(" "
185                                         "<img align=\"middle\" "
186                                         "src=\"static/inactiveuser_24x.gif\" "
187                                         "alt=\"(%s %d %s)\" border=\"0\" />",
188                                         _("idle since"),
189                                         (now - User->LastActive) / 60,
190                                         _("Minutes")
191                                         );
192                                 
193                         }
194                         else {
195                                 wprintf(" "
196                                         "<img align=\"middle\" "
197                                         "src=\"static/activeuser_24x.gif\" "
198                                         "alt=\"(active)\" border=\"0\" />");
199                         }
200                         wprintf("</td>\n<td>");
201
202                         /** username (link to user bio/photo page) */
203                         wprintf("<a href=\"showuser?who=");
204                         urlescputs(User->UserName);
205                         wprintf("\">");
206                         escputs(User->UserName);
207                         if (User->SessionCount > 1)
208                                 wprintf(" [%d] ", User->SessionCount);
209                         wprintf("</a>");
210
211                         /** room */
212                         wprintf("</td>\n\t<td>");
213                         escputs(User->Room);
214                         if (!IsEmptyStr(User->RealRoom) ) {
215                                 wprintf("<br /><i>");
216                                 escputs(User->RealRoom);
217                                 wprintf("</i>");
218                         }
219                         wprintf("</td>\n\t<td class=\"host_col\">");
220
221                         /** hostname */
222                         escputs(User->Host);
223                         if (!IsEmptyStr(User->RealHost)) {
224                                 wprintf("<br /><i>");
225                                 escputs(User->RealHost);
226                                 wprintf("</i>");
227                         }
228                         wprintf("</td>\n</tr>");
229                 }
230                 DeleteHashPos(&it);
231         }
232         wprintf("</table>");
233         DeleteHash(&List);
234
235 }
236
237
238 /**
239  * \brief who is on?
240  */
241 void who(void)
242 {
243         char title[256];
244
245         output_headers(1, 1, 2, 0, 0, 0);
246
247         wprintf("<script type=\"text/javascript\">\n"
248                 "function ConfirmKill() { \n"
249                 "return confirm('%s');\n"
250                 "}\n"
251                 "</script>\n", _("Do you really want to kill this session?")
252         );
253
254         wprintf("<div id=\"banner\">\n");
255         wprintf("<div class=\"room_banner\">");
256         wprintf("<img src=\"static/usermanag_48x.gif\">");
257         wprintf("<h1>");
258         snprintf(title, sizeof title, _("Users currently on %s"), serv_info.serv_humannode);
259         escputs(title);
260         wprintf("</h1></div>");
261         wprintf("<ul class=\"room_actions\">\n");
262         wprintf("<li class=\"start_page\">");
263         offer_start_page();
264         wprintf("</li></ul>");
265         wprintf("</div>");
266
267         wprintf("<div id=\"content\" class=\"fix_scrollbar_bug who_is_online\">\n");
268         wprintf("<div class=\"box\">");
269         wprintf("<div class=\"boxlabel\">");    
270         snprintf(title, sizeof title, _("Users currently on %s"), serv_info.serv_humannode);
271         escputs(title);
272         wprintf("</div>");      
273         wprintf("<div class=\"boxcontent\">");
274         wprintf("<div id=\"who_inner\" >");
275         who_inner_div();
276         wprintf("</div>");
277
278         wprintf("<div class=\"instructions\">");
279         wprintf(_("Click on a name to read user info.  Click on %s "
280                 "to send an instant message to that user."),
281                 "<img align=\"middle\" src=\"static/citadelchat_16x.gif\" alt=\"(p)\" border=\"0\">"
282         );
283         wprintf("</div></div>\n");
284
285         /**
286          * JavaScript to make the ajax refresh happen:
287          * See http://www.sergiopereira.com/articles/prototype.js.html for info on Ajax.PeriodicalUpdater
288          * It wants: 1. The div being updated
289          *           2. The URL of the update source
290          *           3. Other flags (such as the HTTP method and the refresh frequency)
291          */
292         wprintf(
293                 "<script type=\"text/javascript\">                                      "
294                 " new Ajax.PeriodicalUpdater('who_inner', 'who_inner_html',     "
295                 "                            { method: 'get', frequency: 30 }  );       "
296                 "</script>                                                              \n"
297         );
298         wDumpContent(1);
299 }
300
301 /**
302  * \brief end session \todo what??? does this belong here? 
303  */
304 void terminate_session(void)
305 {
306         char buf[SIZ];
307
308         serv_printf("TERM %s", bstr("which_session"));
309         serv_getln(buf, sizeof buf);
310         who();
311 }
312
313
314 /**
315  * \brief Change your session info (fake roomname and hostname)
316  */
317 void edit_me(void)
318 {
319         char buf[SIZ];
320
321         if (!IsEmptyStr(bstr("change_room_name_button"))) {
322                 serv_printf("RCHG %s", bstr("fake_roomname"));
323                 serv_getln(buf, sizeof buf);
324                 http_redirect("who");
325         } else if (!IsEmptyStr(bstr("change_host_name_button"))) {
326                 serv_printf("HCHG %s", bstr("fake_hostname"));
327                 serv_getln(buf, sizeof buf);
328                 http_redirect("who");
329         } else if (!IsEmptyStr(bstr("change_user_name_button"))) {
330                 serv_printf("UCHG %s", bstr("fake_username"));
331                 serv_getln(buf, sizeof buf);
332                 http_redirect("who");
333         } else if (!IsEmptyStr(bstr("cancel_button"))) {
334                 http_redirect("who");
335         } else {
336                 output_headers(1, 1, 0, 0, 0, 0);
337
338                 wprintf("<div id=\"banner\">\n");
339                 wprintf("<table class=\"who_banner\"><tr><td>");
340                 wprintf("<span class=\"titlebar\">");
341                 wprintf(_("Edit your session display"));
342                 wprintf("</span></td></tr></table>\n");
343                 wprintf("</div>\n<div id=\"content\">\n");
344
345                 wprintf(_("This screen allows you to change the way your "
346                         "session appears in the 'Who is online' listing. "
347                         "To turn off any 'fake' name you've previously "
348                         "set, simply click the appropriate 'change' button "
349                         "without typing anything in the corresponding box. "));
350                 wprintf("<br />\n");
351
352                 wprintf("<form method=\"POST\" action=\"edit_me\">\n");
353                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
354
355                 wprintf("<table border=0 width=100%%>\n");
356
357                 wprintf("<tr><td><b>");
358                 wprintf(_("Room name:"));
359                 wprintf("</b></td>\n<td>");
360                 wprintf("<input type=\"text\" name=\"fake_roomname\" maxlength=\"64\">\n");
361                 wprintf("</td>\n<td align=center>");
362                 wprintf("<input type=\"submit\" name=\"change_room_name_button\" value=\"%s\">",
363                         _("Change room name"));
364                 wprintf("</td>\n</tr>\n");
365
366                 wprintf("<tr><td><b>");
367                 wprintf(_("Host name:"));
368                 wprintf("</b></td><td>");
369                 wprintf("<input type=\"text\" name=\"fake_hostname\" maxlength=\"64\">\n");
370                 wprintf("</td>\n<td align=center>");
371                 wprintf("<input type=\"submit\" name=\"change_host_name_button\" value=\"%s\">",
372                         _("Change host name"));
373                 wprintf("</td>\n</tr>\n");
374
375                 if (WC->is_aide) {
376                         wprintf("<tr><td><b>");
377                         wprintf(_("User name:"));
378                         wprintf("</b></td><td>");
379                         wprintf("<input type=\"text\" name=\"fake_username\" maxlength=\"64\">\n");
380                         wprintf("</td>\n<td align=center>");
381                         wprintf("<input type=\"submit\" name \"change_user_name_button\" value=\"%s\">",
382                                 _("Change user name"));
383                         wprintf("</td>\n</tr>\n");
384                 }
385                 wprintf("<tr><td> </td><td> </td><td align=center>");
386                 wprintf("<input type=\"submit\" name=\"cancel_button\" value=\"%s\">",
387                         _("Cancel"));
388                 wprintf("</td></tr></table>\n");
389                 wprintf("</form></center>\n");
390                 wDumpContent(1);
391         }
392 }
393
394 /**
395  * \brief Wholist section
396  */
397 void wholist_section(void) {
398         UserStateStruct *User;
399         void *VUser;
400         HashList *List;
401         HashPos  *it;
402         char *UserName;
403         long len;
404         char buf[SIZ];
405         time_t now;
406
407         serv_puts("TIME");
408         serv_getln(buf, sizeof buf);
409         if (buf[0] == '2') {
410                 now = extract_long(&buf[4], 0);
411         }
412         else {
413                 now = time(NULL);
414         }
415
416         List = NewHash();
417
418         if (GetWholistSection(List, now)) {
419                 SortByPayload(List, CompareUserStruct);
420                 it = GetNewHashPos();
421                 while (GetNextHashPos(List, it, &len, &UserName, &VUser)) {
422                         User = VUser;
423                         if (strcmp(User->UserName, NLI)) {
424                                 wprintf("<li class=\"");
425                                 if (User->Idle) {
426                                         wprintf("inactiveuser");
427                                 }
428                                 else {
429                                         wprintf("activeuser");
430                                 }
431                                 wprintf("\"><a href=\"showuser?who=");
432                                 urlescputs(User->UserName);
433                                 wprintf("\">");
434                                 escputs(User->UserName);
435                                 wprintf("</a></li>");
436                         }
437                 }
438                 DeleteHashPos(&it);
439         }
440         DeleteHash(&List);
441 }
442
443
444
445 /*@}*/