1 /*
2  * tabkey.c: completion for /msg and public chats
3  *
4  * Copyright(c) 1997-2000 - All Rights Reserved
5  *
6  * See the COPYRIGHT file.
7  */
8 
9 #ifndef lint
10 static char rcsid[] = "@(#)$Id: tabkey.c,v 1.14 2000/07/31 22:33:56 kalt Exp $";
11 #endif
12 
13 #include "os.h"
14 
15 #include "struct.h"
16 #include "option.h"
17 
18 extern struct server_ *server;
19 
20 struct nlist_
21 {
22   char		*nick;
23   char		*uh;
24   time_t	ts;
25   struct nlist_	*nextn;
26   struct server_ *svr;
27 };
28 
29 static struct nlist_ *tablist = NULL, *tabnext = NULL;
30 static struct nlist_ *spacelist = NULL, *spacenext = NULL;
31 
32 static time_t lastg = 0;
33 
34 static void
nlist_collect(list)35 nlist_collect(list)
36   struct nlist_ **list;
37 {
38   struct nlist_ **ntmp = list, *del;
39 
40   lastg = time(NULL);
41   while (*ntmp)
42     {
43       if ((lastg - (del = (*ntmp))->ts) > 3600)
44 	{
45 	  /* no need to worry about nicknext here */
46 	  *ntmp = del->nextn;
47 	  free(del->nick);
48 	  if (del->uh)
49 	      free(del->uh);
50 	  free(del);
51 	}
52       else
53 	  ntmp = &((*ntmp)->nextn);
54     }
55 }
56 
57 static char
real_add(list,next,nick,uh)58 real_add(list, next, nick, uh)
59   char *nick, *uh;
60   struct nlist_ **list, **next;
61 {
62   struct nlist_ **ntmp = list, *top;
63   char rc = 0;
64 
65   while (*ntmp)
66     {
67       if (!strcasecmp((*ntmp)->nick, nick) && (*ntmp)->svr == server)
68 	  break;
69       ntmp = &((*ntmp)->nextn);
70     }
71   if (*ntmp)
72     {
73       (*ntmp)->nick = strdup(nick);
74       top = *ntmp;
75       *ntmp = top->nextn;
76       if (uh && *uh && strcmp(top->uh, uh))
77 	{
78 	  free(top->uh);
79 	  top->uh = strdup(uh);
80 	  rc = 1;
81 	}
82       else if ((time(NULL) - top->ts) > 600)
83 	  rc = 1;
84     }
85   else
86     {
87       top = (struct nlist_ *) malloc(sizeof(struct nlist_));
88       top->nick = strdup(nick);
89       top->uh = (uh) ? strdup(uh) : NULL;
90       top->svr = server;
91       rc = 1;
92     }
93   top->ts = time(NULL);
94   top->nextn = *list;
95   *list = top;
96   *next = NULL;
97   if ((time(NULL) - lastg) > 1800)
98       nlist_collect(list);
99   return rc;
100 }
101 
102 /* tab_add: adds a nickname/servicename to the list.
103  *	    uh is the nick's u@h, or "" if irrelevant (DCC, unknown)
104  *	    uh is NULL for services.
105  */
106 char
tab_add(nick,uh)107 tab_add(nick, uh)
108   char *nick, *uh;
109 {
110   return real_add(&tablist, &tabnext, nick, uh);
111 }
112 
113 /* space_add: adds a nickname to the list.
114  *	      uh should be ""
115  */
116 char
space_add(nick,uh)117 space_add(nick, uh)
118   char *nick, *uh;
119 {
120   assert (*uh == '\0');
121 
122   return real_add(&spacelist, &spacenext, nick, uh);
123 }
124 
125 static char *
real_get(list,next)126 real_get(list, next)
127   struct nlist_ *list, **next;
128 {
129   struct nlist_ *loop = (*next) ? *next : list;
130   int looped = 0;
131   struct server_ *smatch = server;
132   static char eresult[512];
133 
134   if (list == tablist && get_option(Z_ETABKEY, NULL))
135       smatch = NULL;
136 
137   do
138     {
139       if (*next == loop)
140 	  looped += 1;
141       if (*next)
142 	{
143 	  if ((*next = (*next)->nextn) == NULL)
144 	      *next = list;
145 	}
146       else
147 	  *next = list;
148     }
149   while ((!*next || ((smatch != NULL && (*next)->svr != smatch)
150 		     && *((*next)->nick) != '='))
151 	 && looped <= 1);
152 
153   if (*next && (*next)->uh == NULL)
154       strcpy(eresult, "@"); /* service */
155   else
156       eresult[0] = '\0'; /* nickname / dcc chat */
157 
158   if (smatch != NULL)
159     {
160       if (*next && ((*next)->svr == server || *((*next)->nick) == '='))
161 	  strcat(eresult, (*next)->nick);
162       else
163 	  eresult[0] = '\0';
164     }
165   else
166       if (*next)
167 	{
168 	  if (*eresult == '@')
169 	      strcat(eresult, (*next)->nick);
170 	  else if ((*next)->nick[0] == '=')
171 	      strcpy(eresult, (*next)->nick);
172 	  else
173 	      sprintf(eresult, "%s@[%s]", (*next)->nick, (*next)->svr->sname);
174 	}
175       else
176 	  eresult[0] = '\0';
177 
178   return eresult;
179 }
180 
181 /* tab_get: returns next nickname in the list. (services prefixed with @) */
182 char *
tab_get()183 tab_get()
184 {
185   return real_get(tablist, &tabnext);
186 }
187 
188 /* space_get: returns next nickname in the list */
189 char *
space_get()190 space_get()
191 {
192   return real_get(spacelist, &spacenext);
193 }
194