templatize userlist
[citadel.git] / webcit / useredit.c
1 /*
2  * Copyright (c) 1996-2011 by the citadel.org team
3  *
4  * This program is open source software.  You can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 3 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */
18
19 #include "webcit.h"
20 #include "webserver.h"
21
22
23 /*
24  *  show a list of available users to edit them
25  *  message the header message???
26  *  preselect = which user should be selected in the browser
27  */
28 void select_user_to_edit(const char *preselect)
29 {
30         output_headers(1, 0, 0, 0, 1, 0);
31         do_template("aide_edituser_select");
32         end_burst();
33 }
34
35
36 typedef struct _UserListEntry {
37         int UID;
38         int AccessLevel;
39         int nLogons;
40         int nPosts;
41
42         StrBuf *UserName;
43         StrBuf *Passvoid;
44         time_t LastLogonT;
45         /* Just available for Single users to view: */
46         unsigned int Flags;
47         int DaysTillPurge;
48         int HasBio;
49 } UserListEntry;
50
51
52 UserListEntry* NewUserListOneEntry(StrBuf *SerializedUser, const char *Pos)
53 {
54         UserListEntry *ul;
55
56         if (StrLength(SerializedUser) < 8) 
57                 return NULL;
58
59         ul = (UserListEntry*) malloc(sizeof(UserListEntry));
60         ul->UserName = NewStrBuf();
61         ul->Passvoid = NewStrBuf();
62
63         StrBufExtract_NextToken(ul->UserName,               SerializedUser, &Pos, '|');
64         StrBufExtract_NextToken(ul->Passvoid,               SerializedUser, &Pos, '|');
65         ul->Flags         = StrBufExtractNext_unsigned_long(SerializedUser, &Pos, '|');
66         ul->nLogons       = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
67         ul->nPosts        = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
68         ul->AccessLevel   = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
69         ul->UID           = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
70         ul->LastLogonT    = StrBufExtractNext_long(         SerializedUser, &Pos, '|');
71         ul->DaysTillPurge = StrBufExtractNext_int(          SerializedUser, &Pos, '|');
72         return ul;
73 }
74
75 void DeleteUserListEntry(void *vUserList)
76 {
77         UserListEntry *ul = (UserListEntry*) vUserList;
78         if (!ul) return;
79         FreeStrBuf(&ul->UserName);
80         FreeStrBuf(&ul->Passvoid);
81         free(ul);
82 }
83
84 UserListEntry* NewUserListEntry(StrBuf *SerializedUserList)
85 {
86         const char *Pos = NULL;
87         UserListEntry *ul;
88
89         if (StrLength(SerializedUserList) < 8) 
90                 return NULL;
91
92         ul = (UserListEntry*) malloc(sizeof(UserListEntry));
93         ul->UserName = NewStrBuf();
94         ul->Passvoid = NewStrBuf();
95
96         StrBufExtract_NextToken(ul->UserName,    SerializedUserList, &Pos, '|');
97         ul->AccessLevel = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
98         ul->UID         = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
99         ul->LastLogonT  = StrBufExtractNext_long(SerializedUserList, &Pos, '|');
100         ul->nLogons     = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
101         ul->nPosts      = StrBufExtractNext_int( SerializedUserList, &Pos, '|');
102         StrBufExtract_NextToken(ul->Passvoid,    SerializedUserList, &Pos, '|');
103         ul->Flags = 0;
104         ul->DaysTillPurge = -1;
105         return ul;
106 }
107
108 /*
109  * Sort by Username
110  */
111 int CompareUserListName(const void *vUser1, const void *vUser2)
112 {
113         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
114         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
115
116         return strcmp(ChrPtr(u1->UserName), ChrPtr(u2->UserName));
117 }
118
119 int CompareUserListNameRev(const void *vUser1, const void *vUser2)
120 {
121         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
122         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
123         return strcmp(ChrPtr(u2->UserName), ChrPtr(u1->UserName));
124 }
125
126 int GroupchangeUserListName(const void *vUser1, const void *vUser2)
127 {
128         UserListEntry *u1 = (UserListEntry*) vUser1;
129         UserListEntry *u2 = (UserListEntry*) vUser2;
130         return ChrPtr(u2->UserName)[0] != ChrPtr(u1->UserName)[0];
131 }
132
133 /*
134  * Sort by access level
135  */
136 int CompareAccessLevel(const void *vUser1, const void *vUser2)
137 {
138         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
139         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
140
141         return (u1->AccessLevel > u2->AccessLevel);
142 }
143
144 int CompareAccessLevelRev(const void *vUser1, const void *vUser2)
145 {
146         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
147         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
148
149         return (u2->AccessLevel > u1->AccessLevel);
150 }
151
152 int GroupchangeAccessLevel(const void *vUser1, const void *vUser2)
153 {
154         UserListEntry *u1 = (UserListEntry*) vUser1;
155         UserListEntry *u2 = (UserListEntry*) vUser2;
156
157         return u2->AccessLevel != u1->AccessLevel;
158 }
159
160 /*
161  * Sort by UID
162  */
163 int CompareUID(const void *vUser1, const void *vUser2)
164 {
165         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
166         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
167
168         return (u1->UID > u2->UID);
169 }
170
171 int CompareUIDRev(const void *vUser1, const void *vUser2)
172 {
173         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
174         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
175
176         return (u2->UID > u1->UID);
177 }
178
179 int GroupchangeUID(const void *vUser1, const void *vUser2)
180 {
181         UserListEntry *u1 = (UserListEntry*) vUser1;
182         UserListEntry *u2 = (UserListEntry*) vUser2;
183
184         return (u2->UID / 10) != (u1->UID / 10);
185 }
186
187 /*
188  * Sort By Date /// TODO!
189  */
190 int CompareLastLogon(const void *vUser1, const void *vUser2)
191 {
192         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
193         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
194
195         return (u1->LastLogonT > u2->LastLogonT);
196 }
197
198 int CompareLastLogonRev(const void *vUser1, const void *vUser2)
199 {
200         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
201         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
202
203         return (u2->LastLogonT > u1->LastLogonT);
204 }
205
206 int GroupchangeLastLogon(const void *vUser1, const void *vUser2)
207 {
208         UserListEntry *u1 = (UserListEntry*) vUser1;
209         UserListEntry *u2 = (UserListEntry*) vUser2;
210
211         return (u2->LastLogonT != u1->LastLogonT);
212 }
213
214 /*
215  * Sort By Number of Logons
216  */
217 int ComparenLogons(const void *vUser1, const void *vUser2)
218 {
219         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
220         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
221
222         return (u1->nLogons > u2->nLogons);
223 }
224
225 int ComparenLogonsRev(const void *vUser1, const void *vUser2)
226 {
227         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
228         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
229
230         return (u2->nLogons > u1->nLogons);
231 }
232
233 int GroupchangenLogons(const void *vUser1, const void *vUser2)
234 {
235         UserListEntry *u1 = (UserListEntry*) vUser1;
236         UserListEntry *u2 = (UserListEntry*) vUser2;
237
238         return (u2->nLogons / 100) != (u1->nLogons / 100);
239 }
240
241 /*
242  * Sort By Number of Posts
243  */
244 int ComparenPosts(const void *vUser1, const void *vUser2)
245 {
246         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
247         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
248
249         return (u1->nPosts > u2->nPosts);
250 }
251
252 int ComparenPostsRev(const void *vUser1, const void *vUser2)
253 {
254         UserListEntry *u1 = (UserListEntry*) GetSearchPayload(vUser1);
255         UserListEntry *u2 = (UserListEntry*) GetSearchPayload(vUser2);
256
257         return (u2->nPosts > u1->nPosts);
258 }
259
260 int GroupchangenPosts(const void *vUser1, const void *vUser2)
261 {
262         UserListEntry *u1 = (UserListEntry*) vUser1;
263         UserListEntry *u2 = (UserListEntry*) vUser2;
264
265         return (u2->nPosts / 100) != (u1->nPosts / 100);
266 }
267
268
269 HashList *iterate_load_userlist(StrBuf *Target, WCTemplputParams *TP)
270 {
271         int Done = 0;
272         CompareFunc SortIt;
273         HashList *Hash = NULL;
274         StrBuf *Buf;
275         UserListEntry* ul;
276         int len;
277         int UID;
278         void *vData;
279         WCTemplputParams SubTP;
280
281         memset(&SubTP, 0, sizeof(WCTemplputParams));    
282         serv_puts("LIST");
283         Buf = NewStrBuf();
284         StrBuf_ServGetln(Buf);
285         if (GetServerStatus(Buf, NULL) == 1) {
286                 Hash = NewHash(1, Flathash);
287
288                 while (!Done) {
289                         len = StrBuf_ServGetln(Buf);
290                         if ((len <0) || 
291                             ((len == 3) &&
292                              !strcmp(ChrPtr(Buf), "000")))
293                         {
294                                 Done = 1;
295                                 break;
296                         }
297                         ul = NewUserListEntry(Buf);
298                         if (ul == NULL)
299                                 continue;
300
301                         Put(Hash, IKEY(ul->UID), ul, DeleteUserListEntry); 
302                 }
303
304                 serv_puts("LBIO 1");
305                 if (GetServerStatus(Buf, NULL) == 1)
306                         while (!Done) {
307                         len = StrBuf_ServGetln(Buf);
308                         if ((len <0) || 
309                             ((len == 3) &&
310                              !strcmp(ChrPtr(Buf), "000")))
311                         {
312                                 Done = 1;
313                                 break;
314                         }
315                         UID = atoi(ChrPtr(Buf));
316                         if (GetHash(Hash, IKEY(UID), &vData) && vData != 0)
317                         {
318                                 ul = (UserListEntry*)vData;
319                                 ul->HasBio = 1;
320                         }
321                 }
322                 SubTP.Filter.ContextType = CTX_USERLIST;
323                 SortIt = RetrieveSort(&SubTP, HKEY("USER"), HKEY("user:uid"), 0);
324                 if (SortIt != NULL)
325                         SortByPayload(Hash, SortIt);
326                 else 
327                         SortByPayload(Hash, CompareUID);
328         }
329         FreeStrBuf(&Buf);
330         return Hash;
331 }
332
333
334 void tmplput_USERLIST_UserName(StrBuf *Target, WCTemplputParams *TP)
335 {
336         UserListEntry *ul = (UserListEntry*) CTX;
337         StrBufAppendTemplate(Target, TP, ul->UserName, 0);
338 }
339
340 void tmplput_USERLIST_Password(StrBuf *Target, WCTemplputParams *TP)
341 {
342         UserListEntry *ul = (UserListEntry*) CTX;
343         StrBufAppendTemplate(Target, TP, ul->Passvoid, 0);
344 }
345
346 void tmplput_USERLIST_AccessLevelNo(StrBuf *Target, WCTemplputParams *TP)
347 {
348         UserListEntry *ul = (UserListEntry*) CTX;
349
350         StrBufAppendPrintf(Target, "%d", ul->AccessLevel, 0);
351 }
352
353 void tmplput_USERLIST_AccessLevelStr(StrBuf *Target, WCTemplputParams *TP)
354 {
355         UserListEntry *ul = (UserListEntry*) CTX;
356         
357         StrBufAppendBufPlain(Target, _(axdefs[ul->AccessLevel]), -1, 0);
358 }
359
360 void tmplput_USERLIST_UID(StrBuf *Target, WCTemplputParams *TP)
361 {
362         UserListEntry *ul = (UserListEntry*) CTX;
363
364         StrBufAppendPrintf(Target, "%d", ul->UID, 0);
365 }
366
367 void tmplput_USERLIST_LastLogonNo(StrBuf *Target, WCTemplputParams *TP)
368 {
369         UserListEntry *ul = (UserListEntry*) CTX;
370
371         StrBufAppendPrintf(Target,"%ld", ul->LastLogonT, 0);
372 }
373 void tmplput_USERLIST_LastLogonStr(StrBuf *Target, WCTemplputParams *TP)
374 {
375         UserListEntry *ul = (UserListEntry*) CTX;
376         StrEscAppend(Target, NULL, asctime(localtime(&ul->LastLogonT)), 0, 0);
377 }
378
379 void tmplput_USERLIST_nLogons(StrBuf *Target, WCTemplputParams *TP)
380 {
381         UserListEntry *ul = (UserListEntry*) CTX;
382
383         StrBufAppendPrintf(Target, "%d", ul->nLogons, 0);
384 }
385
386 void tmplput_USERLIST_nPosts(StrBuf *Target, WCTemplputParams *TP)
387 {
388         UserListEntry *ul = (UserListEntry*) CTX;
389
390         StrBufAppendPrintf(Target, "%d", ul->nPosts, 0);
391 }
392
393 void tmplput_USERLIST_Flags(StrBuf *Target, WCTemplputParams *TP)
394 {
395         UserListEntry *ul = (UserListEntry*) CTX;
396
397         StrBufAppendPrintf(Target, "%d", ul->Flags, 0);
398 }
399
400 void tmplput_USERLIST_DaysTillPurge(StrBuf *Target, WCTemplputParams *TP)
401 {
402         UserListEntry *ul = (UserListEntry*) CTX;
403
404         StrBufAppendPrintf(Target, "%d", ul->DaysTillPurge, 0);
405 }
406
407 int ConditionalUser(StrBuf *Target, WCTemplputParams *TP)
408 {
409         UserListEntry *ul = (UserListEntry*) CTX;
410         if (havebstr("usernum")) {
411                 return ibstr("usernum") == ul->UID;
412         }
413         else if (havebstr("username")) {
414                 return strcmp(bstr("username"), ChrPtr(ul->UserName)) == 0;
415         }
416         else 
417                 return 0;
418 }
419
420 int ConditionalFlagINetEmail(StrBuf *Target, WCTemplputParams *TP)
421 {
422         UserListEntry *ul = (UserListEntry*) CTX;
423         return (ul->Flags & US_INTERNET) != 0;
424 }
425
426 int ConditionalUserAccess(StrBuf *Target, WCTemplputParams *TP)
427 {
428         UserListEntry *ul = (UserListEntry*) CTX;
429         
430         if (ul == NULL)
431                 return 0;
432
433         return GetTemplateTokenNumber(Target, 
434                                       TP, 
435                                       3, 
436                                       AxNewU)
437                 ==
438                 ul->AccessLevel;
439 }
440 int ConditionalHaveBIO(StrBuf *Target, WCTemplputParams *TP)
441 {
442         UserListEntry *ul = (UserListEntry*) CTX;
443         
444         if (ul == NULL)
445                 return 0;
446         return ul->HasBio;
447 }
448
449 void tmplput_USER_BIO(StrBuf *Target, WCTemplputParams *TP)
450 {
451         int Done = 0;
452         StrBuf *Buf;
453         const char *who;
454         long len;
455
456         GetTemplateTokenString(Target, TP, 0, &who, &len);
457
458         Buf = NewStrBuf();
459         serv_printf("RBIO %s", who);
460         StrBuf_ServGetln(Buf);
461         if (GetServerStatus(Buf, NULL) == 1) {
462                 StrBuf *BioBuf = NewStrBufPlain(NULL, SIZ);
463                 while (!Done && StrBuf_ServGetln(Buf)>=0) {
464                         if ( (StrLength(Buf)==3) && 
465                              !strcmp(ChrPtr(Buf), "000")) 
466                                 Done = 1;
467                         else
468                                 StrBufAppendBuf(BioBuf, Buf, 0);
469                 }
470                 StrBufAppendTemplate(Target, TP, BioBuf, 1);
471                 FreeStrBuf(&BioBuf);
472         }
473         FreeStrBuf(&Buf);
474 }
475
476 int Conditional_USER_HAS_PIC(StrBuf *Target, WCTemplputParams *TP)
477 {
478         StrBuf *Buf;
479         const char *who;
480         long len;
481
482         GetTemplateTokenString(Target, TP, 2, &who, &len);
483
484         Buf = NewStrBuf();
485         serv_printf("OIMG _userpic_|%s", who);
486         StrBuf_ServGetln(Buf);
487         if (GetServerStatus(Buf, NULL) != 2) {
488                 serv_puts("CLOS");
489                 StrBuf_ServGetln(Buf);
490                 GetServerStatus(Buf, NULL);
491                 FreeStrBuf(&Buf);
492                 return 1;
493         } else {
494                 FreeStrBuf(&Buf);
495                 return 0;
496         }
497 }
498
499
500 /*
501  *  Locate the message number of a user's vCard in the current room
502  *  Returns the message id of his vcard
503  */
504 long locate_user_vcard_in_this_room(message_summary **VCMsg, wc_mime_attachment **VCAtt)
505 {
506         wcsession *WCC = WC;
507         HashPos *at;
508         HashPos *att;
509         const char *HashKey;
510         long HKLen;
511         void *vMsg;
512         message_summary *Msg;
513         wc_mime_attachment *Att;
514         StrBuf *Buf;
515         long vcard_msgnum = (-1L);
516         int already_tried_creating_one = 0;
517         StrBuf *FoundCharset = NewStrBuf();
518         StrBuf *Error = NULL;
519         SharedMessageStatus Stat;
520
521
522         Buf = NewStrBuf();
523 TRYAGAIN:
524         memset(&Stat, 0, sizeof(SharedMessageStatus));
525         Stat.maxload = 10000;
526         Stat.lowest_found = (-1);
527         Stat.highest_found = (-1);
528         /* Search for the user's vCard */
529         if (load_msg_ptrs("MSGS ALL||||1", &Stat, NULL) > 0) {
530                 at = GetNewHashPos(WCC->summ, 0);
531                 while (GetNextHashPos(WCC->summ, at, &HKLen, &HashKey, &vMsg)) {
532                         Msg = (message_summary*) vMsg;          
533                         Msg->MsgBody =  (wc_mime_attachment*) malloc(sizeof(wc_mime_attachment));
534                         memset(Msg->MsgBody, 0, sizeof(wc_mime_attachment));
535                         Msg->MsgBody->msgnum = Msg->msgnum;
536
537                         load_message(Msg, FoundCharset, &Error);
538                         
539                         if (Msg->AllAttach != NULL) {
540                                 att = GetNewHashPos(Msg->AllAttach, 0);
541                                 while (GetNextHashPos(Msg->AllAttach, att, &HKLen, &HashKey, &vMsg) && 
542                                        (vcard_msgnum == -1)) {
543                                         Att = (wc_mime_attachment*) vMsg;
544                                         if (
545                                                 (strcasecmp(ChrPtr(Att->ContentType), "text/x-vcard") == 0)
546                                                 || (strcasecmp(ChrPtr(Att->ContentType), "text/vcard") == 0)
547                                         ) {
548                                                 *VCAtt = Att;
549                                                 *VCMsg = Msg;
550                                                 vcard_msgnum = Msg->msgnum;
551                                                 if (Att->Data == NULL) {
552                                                         MimeLoadData(Att);
553                                                 }
554                                         }
555                                 }
556                                 DeleteHashPos(&att);
557                         }
558                         FreeStrBuf(&Error);     /* don't care... */
559                         
560                 }
561                 DeleteHashPos(&at);             
562         }
563
564         /* If there's no vcard, create one */
565         if ((*VCMsg == NULL) && (already_tried_creating_one == 0)) {
566                 FlushStrBuf(Buf);
567                 already_tried_creating_one = 1;
568                 serv_puts("ENT0 1|||4");
569                 StrBuf_ServGetln(Buf);
570                 if (GetServerStatus(Buf, NULL) == 4) {
571                         serv_puts("Content-type: text/x-vcard");
572                         serv_puts("");
573                         serv_puts("begin:vcard");
574                         serv_puts("end:vcard");
575                         serv_puts("000");
576                 }
577                 else 
578                         syslog(1, "Error while creating user vcard: %s\n", ChrPtr(Buf));
579                 goto TRYAGAIN;
580         }
581         FreeStrBuf(&Buf);
582         FreeStrBuf(&FoundCharset);
583
584         return(vcard_msgnum);
585 }
586
587
588 /*
589  *  Display the form for editing a user's address book entry
590  *  username the name of the user
591  *  usernum the citadel-uid of the user
592  */
593 void display_edit_address_book_entry(const char *username, long usernum) {
594         wcsession *WCC = WC;
595         message_summary *VCMsg = NULL;
596         wc_mime_attachment *VCAtt = NULL;
597         StrBuf *roomname;
598         StrBuf *Buf;
599         long vcard_msgnum = (-1L);
600
601         /* Locate the user's config room, creating it if necessary */
602         Buf = NewStrBuf();
603         roomname = NewStrBuf();
604         StrBufPrintf(roomname, "%010ld.%s", usernum, USERCONFIGROOM);
605         serv_printf("GOTO %s||1", ChrPtr(roomname));
606         StrBuf_ServGetln(Buf);
607         if (GetServerStatus(Buf, NULL) != 2) {
608                 serv_printf("CRE8 1|%s|5|||1|", ChrPtr(roomname));
609                 StrBuf_ServGetln(Buf);
610                 GetServerStatus(Buf, NULL);
611                 serv_printf("GOTO %s||1", ChrPtr(roomname));
612                 StrBuf_ServGetln(Buf);
613                 if (GetServerStatus(Buf, NULL) != 2) {
614                         FlushStrBuf(WCC->ImportantMsg);
615                         StrBufAppendBuf(WCC->ImportantMsg, Buf, 4);
616                         select_user_to_edit(username);
617                         FreeStrBuf(&Buf);
618                         FreeStrBuf(&roomname);
619                         return;
620                 }
621         }
622         FreeStrBuf(&Buf);
623
624         locate_user_vcard_in_this_room(&VCMsg, &VCAtt);
625
626         if (VCMsg == NULL) {
627                 StrBufPlain(WCC->ImportantMsg, 
628                             _("An error occurred while trying to create or edit this address book entry."), 
629                             0);
630                 select_user_to_edit(username);
631                 FreeStrBuf(&roomname);
632                 return;
633         }
634
635         do_edit_vcard(vcard_msgnum, "1", 
636                       VCMsg,
637                       VCAtt,
638                       "select_user_to_edit", 
639                       ChrPtr(roomname));
640         FreeStrBuf(&roomname);
641 }
642
643
644 void display_edituser(const char *supplied_username, int is_new) {
645         const char *Pos;
646         wcsession *WCC = WC;
647         UserListEntry* UL;
648         StrBuf *Buf;
649         char username[256];
650
651         if (supplied_username != NULL) {
652                 safestrncpy(username, supplied_username, sizeof username);
653         }
654         else {
655                 safestrncpy(username, bstr("username"), sizeof username);
656         }
657
658         Buf = NewStrBuf();
659         serv_printf("AGUP %s", username);
660         StrBuf_ServGetln(Buf);
661         if (GetServerStatus(Buf, NULL) != 2) {
662                 FlushStrBuf(WCC->ImportantMsg);
663                 StrBufAppendBuf(WCC->ImportantMsg, Buf, 4);
664                 select_user_to_edit(username);
665                 FreeStrBuf(&Buf);
666                 return;
667         }
668         else {
669                 Pos = ChrPtr(Buf) + 4;
670                 UL = NewUserListOneEntry(Buf, Pos);
671                 if ((UL != NULL) && havebstr("edit_abe_button")) {
672                         display_edit_address_book_entry(username, UL->UID);
673                 }
674                 else if ((UL != NULL) && havebstr("delete_button")) {
675                         delete_user(username);
676                 }
677                 else if (UL != NULL) {
678                         WCTemplputParams SubTP;
679                         memset(&SubTP, 0, sizeof(WCTemplputParams));
680                         SubTP.Filter.ContextType = CTX_USERLIST;
681                         SubTP.Context = UL;
682                         output_headers(1, 0, 0, 0, 1, 0);
683                         DoTemplate(HKEY("aide_edituser_detailview"), NULL, &SubTP);
684                         end_burst();
685                 }
686                 DeleteUserListEntry(UL);
687                 
688         }
689         FreeStrBuf(&Buf);
690 }
691
692 /*
693  *  do the backend operation of the user edit on the server
694  */
695 void edituser(void) {
696         wcsession *WCC = WC;
697         int is_new = 0;
698         unsigned int flags = 0;
699         const char *username;
700
701         is_new = ibstr("is_new");
702         username = bstr("username");
703
704         if (!havebstr("ok_button")) {
705                 StrBufPlain(WCC->ImportantMsg, _("Changes were not saved."), -1);
706         }       
707         else {
708                 StrBuf *Buf = NewStrBuf();
709
710                 flags = ibstr("flags");
711                 if (yesbstr("inetmail")) {
712                         flags |= US_INTERNET;
713                 }
714                 else {
715                         flags &= ~US_INTERNET ;
716                 }
717
718                 if ((havebstr("newname")) && (strcasecmp(bstr("username"), bstr("newname")))) {
719                         serv_printf("RENU %s|%s", bstr("username"), bstr("newname"));
720                         StrBuf_ServGetln(Buf);
721                         if (GetServerStatus(Buf, NULL) == 2) {
722                                 FlushStrBuf(WCC->ImportantMsg);
723                                 StrBufAppendBuf(WCC->ImportantMsg, Buf, 4);                             
724                         }
725                         else {
726                                 username = bstr("newname");
727                         }
728                 }
729
730                 serv_printf("ASUP %s|%s|%d|%s|%s|%s|%s|%s|%s|",
731                         username,
732                         bstr("password"),
733                         flags,
734                         bstr("timescalled"),
735                         bstr("msgsposted"),
736                         bstr("axlevel"),
737                         bstr("usernum"),
738                         bstr("lastcall"),
739                         bstr("purgedays")
740                 );
741                 StrBuf_ServGetln(Buf);
742                 if (GetServerStatus(Buf, NULL) == 2) {
743                         StrBufAppendBuf(WCC->ImportantMsg, Buf, 4);
744                 }
745                 FreeStrBuf(&Buf);
746         }
747
748         /*
749          * If we are in the middle of creating a new user, move on to
750          * the vCard edit screen.
751          */
752         if (is_new) {
753                 display_edit_address_book_entry(username, lbstr("usernum") );
754         }
755         else {
756                 select_user_to_edit(username);
757         }
758 }
759
760 /*
761  *  burge a user 
762  *  username the name of the user to remove
763  */
764 void delete_user(char *username) {
765         wcsession *WCC = WC;
766         StrBuf *Buf;
767         
768         Buf = NewStrBuf();
769         serv_printf("ASUP %s|0|0|0|0|0|", username);
770         StrBuf_ServGetln(Buf);
771         if (GetServerStatus(Buf, NULL) != 2) 
772                 StrBufAppendBuf(WCC->ImportantMsg, Buf, 4);
773
774         select_user_to_edit( bstr("username"));
775         FreeStrBuf(&Buf);
776 }
777                 
778
779
780 /*
781  *  create a new user
782  * take the web environment username and create it on the citadel server
783  */
784 void create_user(void) {
785         wcsession *WCC = WC;
786         long FullState;
787         StrBuf *Buf;
788         const char *username;
789
790         Buf = NewStrBuf();
791         username = bstr("username");
792         serv_printf("CREU %s", username);
793         StrBuf_ServGetln(Buf);
794         if (GetServerStatus(Buf, &FullState) == 2) {
795                 sprintf(WC->ImportantMessage, _("A new user has been created."));
796                 display_edituser(username, 1);
797         }
798         else if (FullState == 570) {
799                 StrBufPlain(WCC->ImportantMsg, 
800                             _("You are attempting to create a new user from within Citadel "
801                               "while running in host based authentication mode.  In this mode, "
802                               "you must create new users on the host system, not within Citadel."), 
803                             0);
804                 select_user_to_edit(NULL);
805         }
806         else {
807                 StrBufAppendBuf(WCC->ImportantMsg, Buf, 4);
808                 select_user_to_edit(NULL);
809         }
810         FreeStrBuf(&Buf);
811 }
812
813
814 void _select_user_to_edit(void) {
815         select_user_to_edit(NULL);
816 }
817
818
819 void _display_edituser(void) {
820         display_edituser(NULL, 0);
821 }
822
823 void showuser(void) { do_template("user_show");}
824
825
826 void 
827 InitModule_USEREDIT
828 (void)
829 {
830         WebcitAddUrlHandler(HKEY("showuser"), "", 0, showuser, 0);
831         WebcitAddUrlHandler(HKEY("select_user_to_edit"), "", 0, _select_user_to_edit, 0);
832         WebcitAddUrlHandler(HKEY("display_edituser"), "", 0, _display_edituser, 0);
833         WebcitAddUrlHandler(HKEY("edituser"), "", 0, edituser, 0);
834         WebcitAddUrlHandler(HKEY("create_user"), "", 0, create_user, 0);
835
836         RegisterNamespace("USERLIST:USERNAME",      0, 1, tmplput_USERLIST_UserName, NULL, CTX_USERLIST);
837         RegisterNamespace("USERLIST:PASSWD",        0, 1, tmplput_USERLIST_Password, NULL, CTX_USERLIST);
838         RegisterNamespace("USERLIST:ACCLVLNO",      0, 0, tmplput_USERLIST_AccessLevelNo, NULL, CTX_USERLIST);
839         RegisterNamespace("USERLIST:ACCLVLSTR",     0, 0, tmplput_USERLIST_AccessLevelStr, NULL, CTX_USERLIST);
840         RegisterNamespace("USERLIST:UID",           0, 0, tmplput_USERLIST_UID, NULL, CTX_USERLIST);
841         RegisterNamespace("USERLIST:LASTLOGON:STR", 0, 0, tmplput_USERLIST_LastLogonStr, NULL, CTX_USERLIST);
842         RegisterNamespace("USERLIST:LASTLOGON:NO",  0, 0, tmplput_USERLIST_LastLogonNo, NULL, CTX_USERLIST);
843         RegisterNamespace("USERLIST:NLOGONS",       0, 0, tmplput_USERLIST_nLogons, NULL, CTX_USERLIST);
844         RegisterNamespace("USERLIST:NPOSTS",        0, 0, tmplput_USERLIST_nPosts, NULL, CTX_USERLIST);
845                                                     
846         RegisterNamespace("USERLIST:FLAGS",         0, 0, tmplput_USERLIST_Flags, NULL, CTX_USERLIST);
847         RegisterNamespace("USERLIST:DAYSTILLPURGE", 0, 0, tmplput_USERLIST_DaysTillPurge, NULL, CTX_USERLIST);
848
849         RegisterNamespace("USER:BIO", 1, 2, tmplput_USER_BIO,  NULL, CTX_NONE);
850
851         RegisterConditional(HKEY("COND:USERNAME"),  0,    ConditionalUser, CTX_USERLIST);
852         RegisterConditional(HKEY("COND:USERACCESS"), 0,   ConditionalUserAccess, CTX_USERLIST);
853         RegisterConditional(HKEY("COND:USERLIST:FLAG:USE_INTERNET"), 0, ConditionalFlagINetEmail, CTX_USERLIST);
854         RegisterConditional(HKEY("COND:USERLIST:HAVEBIO"), 0, ConditionalHaveBIO, CTX_USERLIST);
855
856         RegisterConditional(HKEY("COND:USER:PIC"), 1, Conditional_USER_HAS_PIC,  CTX_NONE);
857
858         RegisterIterator("USERLIST", 0, NULL, iterate_load_userlist, NULL, DeleteHash, CTX_USERLIST, CTX_NONE, IT_FLAG_DETECT_GROUPCHANGE);
859         
860
861
862         RegisterSortFunc(HKEY("user:name"),
863                          HKEY("userlist"),
864                          CompareUserListName,
865                          CompareUserListNameRev,
866                          GroupchangeUserListName,
867                          CTX_USERLIST);
868         RegisterSortFunc(HKEY("user:accslvl"),
869                          HKEY("userlist"),
870                          CompareAccessLevel,
871                          CompareAccessLevelRev,
872                          GroupchangeAccessLevel,
873                          CTX_USERLIST);
874
875         RegisterSortFunc(HKEY("user:nlogons"),
876                          HKEY("userlist"),
877                          ComparenLogons,
878                          ComparenLogonsRev,
879                          GroupchangenLogons,
880                          CTX_USERLIST);
881
882         RegisterSortFunc(HKEY("user:uid"),
883                          HKEY("userlist"),
884                          CompareUID,
885                          CompareUIDRev,
886                          GroupchangeUID,
887                          CTX_USERLIST);
888
889         RegisterSortFunc(HKEY("user:lastlogon"),
890                          HKEY("userlist"),
891                          CompareLastLogon,
892                          CompareLastLogonRev,
893                          GroupchangeLastLogon,
894                          CTX_USERLIST);
895
896         RegisterSortFunc(HKEY("user:nmsgposts"),
897                          HKEY("userlist"),
898                          ComparenPosts,
899                          ComparenPostsRev,
900                          GroupchangenPosts,
901                          CTX_USERLIST);
902
903         REGISTERTokenParamDefine(AxDeleted);
904         REGISTERTokenParamDefine(AxNewU);
905         REGISTERTokenParamDefine(AxProbU);
906         REGISTERTokenParamDefine(AxLocU);
907         REGISTERTokenParamDefine(AxNetU);
908         REGISTERTokenParamDefine(AxPrefU);
909         REGISTERTokenParamDefine(AxAideU);
910 }
911