#include "ttt-error.h"
#include "ttt-socket.h"
+struct _ttt_invite {
+ ttt_client_t *actor;
+ ttt_client_t *invitee;
+};
+
struct _ttt_server {
pthread_mutex_t mutex;
- const char *host;
- const char *port;
+ const char *host;
+ const char *port;
- ttt_client_t **clients;
- int clients_size;
- int num_clients;
+ ttt_client_t **clients;
+ int clients_size;
+ int num_clients;
+
+ ttt_invite_t **invites;
+ int invites_size;
+ int num_invites;
};
static void
server->clients = NULL;
server->clients_size = 0;
server->num_clients = 0;
+
+ server->invites = NULL;
+ server->invites_size = 0;
+ server->num_invites = 0;
}
/* Exported: See ttt-server.h for documentation. */
return TTT_ERROR_INVALID_NAME;
for (i = 0; i < server->num_clients; i++) {
- if (strcmp (ttt_client_get_username (server->clients[i]), username) == 0) {
+ if (strcasecmp (ttt_client_get_username (server->clients[i]), username) == 0) {
error = TTT_ERROR_INVALID_NAME;
goto CLEANUP_LOCK;
}
server->clients_size * sizeof (ttt_client_t *));
}
- server->clients [server->num_clients - 1] = client;
+ server->clients[server->num_clients - 1] = client;
CLEANUP_LOCK:
pthread_mutex_unlock (&server->mutex);
void
ttt_server_unregister_client (ttt_server_t *server, ttt_client_t *client)
{
+ ttt_invite_t *invite;
+ char *notice;
+ ttt_bool_t send_notice = FALSE;
int i;
pthread_mutex_lock (&server->mutex);
+ /* Auto-retract and decline pending notices */
+ /* Notices are sent after mutex unlock */
+ for (i = 0; i < server->num_invites; i++)
+ {
+ invite = server->invites[i];
+ if ((invite->actor == client) || (invite->invitee == client))
+ {
+ send_notice = TRUE;
+ if (invite->actor == client)
+ xasprintf (¬ice, "%s" "NOTICE RETRACT %s %s\r\n",
+ notice,
+ ttt_client_get_username(invite->actor),
+ ttt_client_get_username(invite->invitee));
+ else
+ xasprintf (¬ice, "%s" "NOTICE DECLINE %s %s\r\n",
+ notice,
+ ttt_client_get_username(invite->invitee),
+ ttt_client_get_username(invite->actor));
+
+ memmove (&server->invites[i], &server->invites[i+1],
+ (server->num_invites - i - 1) * sizeof (ttt_invite_t *));
+ server->num_invites--;
+ i--;
+ }
+ }
+
for (i = 0; i < server->num_clients; i++)
if (server->clients[i] == client)
break;
server->num_clients--;
pthread_mutex_unlock (&server->mutex);
+
+ if (send_notice)
+ {
+ ttt_server_broadcast(server, notice);
+ free (notice);
+ }
}
/* Exported: See ttt-server.h for documentation. */
/* Exported: See ttt-server.h for documentation. */
ttt_error_t
-ttt_server_statistics (ttt_server_t *server, const char *username, char **response)
+ttt_server_verify_username (ttt_server_t *server,
+ const char *username)
+{
+ ttt_client_t *client;
+
+ return ttt_server_get_client_from_username (server,
+ username,
+ &client);
+}
+
+/* Exported: See ttt-server.h for documentation. */
+ttt_error_t
+ttt_server_get_client_from_username (ttt_server_t *server,
+ const char *username,
+ ttt_client_t **client)
{
ttt_bool_t usernamefound = FALSE;
const char *client_username;
- int client_num_wins;
int i;
pthread_mutex_lock (&server->mutex);
for (i = 0; i < server->num_clients; i++) {
client_username = ttt_client_get_username (server->clients[i]);
- if (strcasecmp (username, client_username) == 0) {
+ if (strcasecmp (username, client_username) == 0)
+ {
usernamefound = TRUE;
- client_num_wins = ttt_client_get_num_wins (server->clients[i]);
- xasprintf (response, "STATISTICS %s \"\r\n"
- "TICTACTOE WINS %d\r\n\"\r\n",
- client_username,
- client_num_wins);
+ *client = server->clients[i];
}
}
/* Exported: See ttt-server.h for documentation. */
ttt_error_t
-ttt_server_verify_username (ttt_server_t *server, const char *username)
+ttt_server_add_invite (ttt_server_t *server,
+ ttt_client_t *actor,
+ ttt_client_t *invitee)
{
- ttt_bool_t usernamefound = FALSE;
- const char *client_username;
- int i;
+ ttt_invite_t *invite;
pthread_mutex_lock (&server->mutex);
- for (i = 0; i < server->num_clients; i++) {
- client_username = ttt_client_get_username (server->clients[i]);
- if (strcasecmp (username, client_username) == 0)
- usernamefound = TRUE;
+ invite = xmalloc (sizeof (ttt_invite_t));
+
+ invite->actor = actor;
+ invite->invitee = invitee;
+
+ server->num_invites++;
+
+ if (server->num_invites > server->invites_size) {
+ if (server->invites_size == 0)
+ server->invites_size = 1;
+ else
+ server->invites_size *= 2;
+
+ server->invites = xrealloc (server->invites,
+ server->invites_size * sizeof (ttt_invite_t *));
}
- pthread_mutex_unlock (&server->mutex);
+ server->invites[server->num_invites - 1] = invite;
- if (!usernamefound)
- return TTT_ERROR_NO_USER;
+ pthread_mutex_unlock (&server->mutex);
return TTT_ERROR_NONE;
}
+/* Exported: See ttt-server.h for documentation. */
+ttt_error_t
+ttt_server_remove_invite (ttt_server_t *server,
+ ttt_client_t *actor,
+ ttt_client_t *invitee)
+{
+ ttt_invite_t *invite;
+ ttt_error_t error;
+ int i;
+
+ pthread_mutex_lock (&server->mutex);
+
+ error = TTT_ERROR_NO_INVITE;
+ for (i = 0; i < server->num_invites; i++)
+ {
+ invite = server->invites[i];
+ if ((invite->actor == actor) && (invite->invitee == invitee))
+ {
+ error = TTT_ERROR_NONE;
+ break;
+ }
+ }
+
+ if (error)
+ goto CLEANUP_LOCK;
+
+ assert (i < server->num_invites);
+
+ memmove (&server->invites[i], &server->invites[i+1],
+ (server->num_invites - i - 1) * sizeof (ttt_invite_t *));
+
+ server->num_invites--;
+
+ CLEANUP_LOCK:
+ pthread_mutex_unlock (&server->mutex);
+
+ return error;
+}
+
/* Exported: See ttt-server.h for documentation. */
const char*
ttt_server_get_host (ttt_server_t *server)
" telnet %s %s\r\n"
"\r\n"
"The TTTP (tic-tac-toe protocol) has been partially implemented.\r\n"
-"The following commands should work: HELO, HELP, MESSAGE, VERSION, QUIT, WHO.\r\n"
+"The following commands should work: HELO, HELP, INVITE, ACCEPT, RETRACT, DECLINE, MESSAGE, STATISTICS, QUIT, VERSION, WHO.\r\n"
"\r\n";
static void