+ assert(!from || cli_verify(from));
+
+ cptr = alloc_client();
+
+ assert(0 != cptr);
+ assert(!cli_magic(cptr));
+ assert(0 == from || 0 != cli_connect(from));
+
+ if (!from) { /* local client, allocate a struct Connection */
+ struct Connection *con = alloc_connection();
+
+ assert(0 != con);
+ assert(!con_magic(con));
+
+ con_magic(con) = CONNECTION_MAGIC;
+ con_fd(con) = -1; /* initialize struct Connection */
+ con_freeflag(con) = 0;
+ con_nextnick(con) = CurrentTime - NICK_DELAY;
+ con_nexttarget(con) = CurrentTime - (TARGET_DELAY * (STARTTARGETS - 1));
+ con_handler(con) = UNREGISTERED_HANDLER;
+ con_client(con) = cptr;
+
+ cli_connect(cptr) = con; /* set the connection and other fields */
+ cli_since(cptr) = cli_lasttime(cptr) = cli_firsttime(cptr) = CurrentTime;
+ cli_lastnick(cptr) = TStime();
+ } else
+ cli_connect(cptr) = cli_connect(from); /* use 'from's connection */
+
+ assert(con_verify(cli_connect(cptr)));
+
+ cli_magic(cptr) = CLIENT_MAGIC;
+ cli_status(cptr) = status;
+ cli_hnext(cptr) = cptr;
+ strcpy(cli_username(cptr), "unknown");
+
+ return cptr;
+}
+
+/** Release a Connection.
+ * @param[in] con Connection to free.
+ */
+void free_connection(struct Connection* con)
+{
+ if (!con)
+ return;
+
+ assert(con_verify(con));
+ assert(0 == con_client(con));
+
+ dealloc_connection(con); /* deallocate the connection */
+}
+
+/** Release a Client.
+ * In addition to the cleanup done by dealloc_client(), this will free
+ * any pending auth request, free the connection for local clients,
+ * and delete the processing timer for the client.
+ * @param[in] cptr Client to free.
+ */
+void free_client(struct Client* cptr)
+{
+ if (!cptr)
+ return;
+ /*
+ * forget to remove the client from the hash table?
+ */
+ assert(cli_verify(cptr));
+ assert(cli_hnext(cptr) == cptr);
+ /* or from linked list? */
+ assert(cli_next(cptr) == 0);
+ assert(cli_prev(cptr) == 0);
+
+ Debug((DEBUG_LIST, "Freeing client %s [%p], connection %p", cli_name(cptr),
+ cptr, cli_connect(cptr)));
+
+ if (cli_auth(cptr))
+ destroy_auth_request(cli_auth(cptr));
+
+ /* Make sure we didn't magically get re-added to the list */
+ assert(cli_next(cptr) == 0);
+ assert(cli_prev(cptr) == 0);
+
+ if (cli_from(cptr) == cptr) { /* in other words, we're local */
+ cli_from(cptr) = 0;
+ /* timer must be marked as not active */
+ if (!cli_freeflag(cptr) && !t_active(&(cli_proc(cptr))))
+ dealloc_connection(cli_connect(cptr)); /* connection not open anymore */
+ else {
+ if (-1 < cli_fd(cptr) && cli_freeflag(cptr) & FREEFLAG_SOCKET)
+ socket_del(&(cli_socket(cptr))); /* queue a socket delete */
+ if (cli_freeflag(cptr) & FREEFLAG_TIMER)
+ timer_del(&(cli_proc(cptr))); /* queue a timer delete */
+ }