+ list_add_tail(&token->node, &client->tokens);
+ client->tokencount++;
+}
+
+bool_t Client_token_match(client_t *client, char const *str)
+{
+ token_t *token;
+ struct dlist *itr;
+
+ if (list_empty(&client->tokens))
+ return false;
+ list_iterate(itr, &client->tokens) {
+ token = list_get_entry(itr, token_t, node);
+ if (strncasecmp(token->token, str, MAX_TOKENSIZE) == 0)
+ return true;
+ }
+ return false;
+}
+
+void Client_token_free(client_t *client)
+{
+ struct dlist *itr, *save;
+ token_t *token;
+
+ list_iterate_safe(itr, save, &client->tokens) {
+ token = list_get_entry(itr, token_t, node);
+ list_del(&token->node);
+ free(token->token);
+ free(token);
+ }
+ client->tokencount = 0;
+}
+
+
+#define OPUS_WARN_USING "<strong>WARNING:</strong> Your client doesn't support the Opus codec the server is using, you won't be able to talk or hear anyone. Please upgrade your Mumble client."
+#define OPUS_WARN_SWITCHING "<strong>WARNING:</strong> Your client doesn't support the Opus codec the server is switching to, you won't be able to talk or hear anyone. Please upgrade your Mumble client."
+void recheckCodecVersions(client_t *connectingClient)
+{
+ client_t *client_itr = NULL;
+ int max = 0, version, current_version;
+ int users = 0, opus = 0;
+ message_t *sendmsg;
+ struct dlist codec_list, *itr, *save;
+ codec_t *codec_itr, *cd;
+ bool_t found;
+ bool_t enableOpus;
+
+ init_list_entry(&codec_list);
+
+ while (Client_iterate(&client_itr) != NULL) {
+ codec_itr = NULL;
+ if (client_itr->codec_count == 0 && !client_itr->bOpus)
+ continue;
+ while (Client_codec_iterate(client_itr, &codec_itr) != NULL) {
+ found = false;
+ list_iterate(itr, &codec_list) {
+ cd = list_get_entry(itr, codec_t, node);
+ if (cd->codec == codec_itr->codec) {
+ cd->count++;
+ found = true;
+ }
+ }
+ if (!found) {
+ cd = malloc(sizeof(codec_t));
+ if (!cd)
+ Log_fatal("Out of memory");
+ memset(cd, 0, sizeof(codec_t));
+ init_list_entry(&cd->node);
+ cd->codec = codec_itr->codec;
+ cd->count = 1;
+ list_add_tail(&cd->node, &codec_list);
+ }
+ }
+ users++;
+ if (client_itr->bOpus)
+ opus++;
+ }
+ if (users == 0)
+ return;
+
+ enableOpus = ((opus * 100 / users) >= getIntConf(OPUS_THRESHOLD));
+
+ list_iterate(itr, &codec_list) {
+ cd = list_get_entry(itr, codec_t, node);
+ if (cd->count > max) {
+ max = cd->count;
+ version = cd->codec;
+ }
+ }
+ list_iterate_safe(itr, save, &codec_list) {
+ list_del(&list_get_entry(itr, codec_t, node)->node);
+ free(list_get_entry(itr, codec_t, node));
+ }
+
+ current_version = bPreferAlpha ? iCodecAlpha : iCodecBeta;
+ if (current_version != version) {
+ // If we don't already use the compat bitstream version set
+ // it as alpha and announce it. If another codec now got the
+ // majority set it as the opposite of the currently valid bPreferAlpha
+ // and announce it.
+ if (version == (uint32_t)0x8000000b)
+ bPreferAlpha = true;
+ else
+ bPreferAlpha = !bPreferAlpha;
+
+ if (bPreferAlpha)
+ iCodecAlpha = version;
+ else
+ iCodecBeta = version;
+ } else if (bOpus && enableOpus) {
+ if (connectingClient && !connectingClient->bOpus)
+ Client_textmessage(connectingClient, OPUS_WARN_USING);
+ return;
+ }
+
+ sendmsg = Msg_create(CodecVersion);
+ sendmsg->payload.codecVersion->alpha = iCodecAlpha;
+ sendmsg->payload.codecVersion->beta = iCodecBeta;
+ sendmsg->payload.codecVersion->prefer_alpha = bPreferAlpha;
+ sendmsg->payload.codecVersion->has_opus = true;
+ sendmsg->payload.codecVersion->opus = enableOpus;
+
+ Client_send_message_except(NULL, sendmsg);
+
+ if (enableOpus && !bOpus) {
+ client_itr = NULL;
+ while (Client_iterate(&client_itr) != NULL) {
+ if ((client_itr->authenticated || client_itr == connectingClient) &&
+ !client_itr->bOpus) {
+ Client_textmessage(client_itr, OPUS_WARN_SWITCHING);
+ }
+ }
+ Log_info("OPUS codec %s", bOpus ? "enabled" : "disabled");
+ }
+
+ bOpus = enableOpus;
+}
+
+static int findFreeSessionId()
+{
+ int id;
+ client_t *itr = NULL;
+
+ for (id = 1; id < INT_MAX; id++) {
+ itr = NULL;
+ while ((itr = Client_iterate(&itr)) != NULL) {
+ if (itr->sessionId == id)
+ break;
+ }
+ if (itr == NULL) /* Found free id */
+ return id;
+ }
+ return -1;
+}
+
+int Client_add(int fd, struct sockaddr_storage *remote)
+{
+ client_t* newclient;
+ message_t *sendmsg;
+ char* addressString = NULL;
+
+ if (Ban_isBannedAddr(remote)) {
+ addressString = Util_addressToString(remote);
+ Log_info("Address %s banned. Disconnecting", addressString);
+ free(addressString);
+ return -1;
+ }
+
+ if ((newclient = calloc(1, sizeof(client_t))) == NULL)
+ Log_fatal("(%s:%s): Out of memory while allocating %d bytes.", __FILE__, __LINE__, sizeof(client_t));