/*
 * Purple - Internet Messaging Library
 * Copyright (C) Pidgin Developers <devel@pidgin.im>
 *
 * Purple is the legal property of its developers, whose names are too numerous
 * to list here. Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this library; if not, see <https://www.gnu.org/licenses/>.
 */

#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
# error "only <purple.h> may be included directly"
#endif

#ifndef PURPLE_CONNECTION_H
#define PURPLE_CONNECTION_H

#include <glib.h>
#include <glib-object.h>

#include <gio/gio.h>

#include <birb.h>

#include "purpleversion.h"

G_BEGIN_DECLS

/**
 * PurpleConnection:
 *
 * Represents an active connection on an account.
 *
 * Since: 2.0
 */

#define PURPLE_TYPE_CONNECTION (purple_connection_get_type())

PURPLE_AVAILABLE_IN_3_0
G_DECLARE_DERIVABLE_TYPE(PurpleConnection, purple_connection, PURPLE,
                         CONNECTION, GObject)

/**
 * PurpleConnectionState:
 * @PURPLE_CONNECTION_STATE_DISCONNECTED: Disconnected
 * @PURPLE_CONNECTION_STATE_DISCONNECTING: Disconnecting
 * @PURPLE_CONNECTION_STATE_CONNECTED: Connected
 * @PURPLE_CONNECTION_STATE_CONNECTING: Connecting
 *
 * A representation of the state of a [class@Purple.Connection].
 *
 * Since: 2.0
 */
typedef enum {
	PURPLE_CONNECTION_STATE_DISCONNECTED PURPLE_AVAILABLE_ENUMERATOR_IN_3_0 = 0,
	PURPLE_CONNECTION_STATE_DISCONNECTING PURPLE_AVAILABLE_ENUMERATOR_IN_3_0,
	PURPLE_CONNECTION_STATE_CONNECTED PURPLE_AVAILABLE_ENUMERATOR_IN_3_0,
	PURPLE_CONNECTION_STATE_CONNECTING PURPLE_AVAILABLE_ENUMERATOR_IN_3_0
} PurpleConnectionState;

/**
 * PURPLE_CONNECTION_ERROR:
 *
 * Error domain for Purple connection errors. Errors in this domain will be
 * from the #PurpleConnectionError enum.
 *
 * Since: 3.0
 */
#define PURPLE_CONNECTION_ERROR \
	g_quark_from_static_string("purple-connection-error") \
	PURPLE_AVAILABLE_MACRO_IN_3_0

/**
 * PurpleConnectionError:
 * @PURPLE_CONNECTION_ERROR_NETWORK_ERROR: There was an error sending or
 *         receiving on the network socket, or there was some protocol error
 *         (such as the server sending malformed data).
 * @PURPLE_CONNECTION_ERROR_INVALID_SETTINGS: The username/server/other
 *         preference for the account isn't valid.  For instance, on IRC the
 *         username cannot contain white space.  This reason should not be used
 *         for incorrect passwords etc: use
 *         #PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED for that.
 * @PURPLE_CONNECTION_ERROR_CUSTOM_TEMPORARY: A custom error that is temporary.
 * @PURPLE_CONNECTION_ERROR_CUSTOM_FATAL: A custom error that is fatal.
 * @PURPLE_CONNECTION_ERROR_OTHER_ERROR: Some other error occurred which fits
 *         into none of the other categories.
 *
 * Possible errors that can cause a connection to be closed.
 *
 * Since: 2.0
 */
typedef enum
{
	PURPLE_CONNECTION_ERROR_NETWORK_ERROR = 0,
	/* TODO This reason really shouldn't be necessary. Usernames and
	 *      other account preferences should be validated when the
	 *      account is created. */
	PURPLE_CONNECTION_ERROR_INVALID_SETTINGS = 7,
	PURPLE_CONNECTION_ERROR_CUSTOM_TEMPORARY = 16,
	PURPLE_CONNECTION_ERROR_CUSTOM_FATAL = 17,

	/* purple_connection_error() in connection.c uses the fact that
	 * this is the last member of the enum when sanity-checking; if other
	 * reasons are added after it, the check must be updated.
	 */
	PURPLE_CONNECTION_ERROR_OTHER_ERROR = 18,

	/**
	 * PURPLE_CONNECTION_ERROR_VFUNC_NOT_IMPLEMENTED:
	 *
	 * An error for when a virtual function is not implemented.
	 *
	 * Since: 3.0
	 */
	PURPLE_CONNECTION_ERROR_VFUNC_NOT_IMPLEMENTED PURPLE_AVAILABLE_ENUMERATOR_IN_3_0,
} PurpleConnectionError;

#include "purpleaccount.h"
#include "purplesavedpresence.h"

struct _PurpleConnectionClass {
	/*< private >*/
	GObjectClass parent;

	gboolean (*connect)(PurpleConnection *connection, GError **error);
	gboolean (*disconnect)(PurpleConnection *connection, const char *message, GError **error);

	void (*set_presence)(PurpleConnection *connection, PurpleSavedPresence *presence);

	BirbActionMenu *(*get_action_menu)(PurpleConnection *connection);

	void (*set_display_name_async)(PurpleConnection *connection, const char *display_name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data);
	gboolean (*set_display_name_finish)(PurpleConnection *connection, GAsyncResult *result, GError **error);

	/*< private >*/
	gpointer reserved[8];
};

/**
 * purple_connection_connect:
 * @error: (out) (nullable): a return address for a #GError
 *
 * Tells the connection to connect.
 *
 * Due to the asynchronous nature of network connections, the return value and
 * @error are to be used to do some initial validation before a connection is
 * actually attempted.
 *
 * Returns: true if the initial connection for @account was successful.
 *
 * Since: 3.0
 */
PURPLE_AVAILABLE_IN_3_0
gboolean purple_connection_connect(PurpleConnection *connection, GError **error);

/**
 * purple_connection_disconnect:
 * @message: (nullable): an optional disconnect message
 * @error: (out) (nullable): a return address for a #GError
 *
 * Tells the connection to disconnect.
 *
 * Returns: true if the account was disconnected gracefully.
 *
 * Since: 3.0
 */
PURPLE_AVAILABLE_IN_3_0
gboolean purple_connection_disconnect(PurpleConnection *connection, const char *message, GError **error);

/**
 * purple_connection_get_account:
 *
 * Gets the connection's account.
 *
 * Returns: (transfer none): The connection's account.
 *
 * Since: 2.0
 */
PURPLE_AVAILABLE_IN_ALL
PurpleAccount *purple_connection_get_account(PurpleConnection *connection);

/**
 * purple_connection_get_action_menu:
 *
 * Gets an action menu for the connection.
 *
 * Returns: (transfer full) (nullable): The new action menu.
 *
 * Since: 3.0
 */
PURPLE_AVAILABLE_IN_3_0
BirbActionMenu *purple_connection_get_action_menu(PurpleConnection *connection);

/**
 * purple_connection_get_cancellable:
 *
 * Gets the cancellable that should be used with @connection.
 *
 * Returns: (transfer none): The cancellable.
 *
 * Since: 3.0
 */
PURPLE_AVAILABLE_IN_3_0
GCancellable *purple_connection_get_cancellable(PurpleConnection *connection);

/**
 * purple_connection_get_id:
 *
 * Gets the identifier of the connection.
 *
 * Returns: The identifier of the connection.
 *
 * Since: 3.0
 */
PURPLE_AVAILABLE_IN_3_0
const char *purple_connection_get_id(PurpleConnection *connection);

/**
 * purple_connection_get_password:
 *
 * Gets the connection's password.
 *
 * Returns: The connection's password.
 *
 * Since: 2.0
 */
PURPLE_AVAILABLE_IN_ALL
const char *purple_connection_get_password(PurpleConnection *connection);

/**
 * purple_connection_implements_set_display_name:
 *
 * Checks whether or not the connection supports setting a display name.
 *
 * Returns: true if setting the display name is possible.
 *
 * Since: 3.0
 */
PURPLE_AVAILABLE_IN_3_0
gboolean purple_connection_implements_set_display_name(PurpleConnection *connection);

/**
 * purple_connection_set_display_name_async:
 * @display_name: (nullable): the new display name
 * @cancellable: (nullable): the cancellable
 * @callback: (scope async): the optional callback
 * @data: (nullable): the user data to pass to the callback
 *
 * Ask the connection to set the display name.
 *
 * Since: 3.0
 */
PURPLE_AVAILABLE_IN_3_0
void purple_connection_set_display_name_async(PurpleConnection *connection, const char *display_name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data);

/**
 * purple_connection_set_display_name_finish:
 * @result: the result
 * @error: (out) (nullable): a return address for a #GError
 *
 * Finishes a previous call to [method@Connection.set_display_name_async].
 *
 * Returns: true if the display name was set successfully.
 *
 * Since: 3.0
 */
PURPLE_AVAILABLE_IN_3_0
gboolean purple_connection_set_display_name_finish(PurpleConnection *connection, GAsyncResult *result, GError **error);

/**
 * purple_connection_set_password:
 * @password: (nullable): the new password
 *
 * Sets the password for the connection.
 *
 * This will not change your password on the remote service. It just updates
 * the password that the protocol should use when connecting.
 *
 * This is generally used by protocol plugins that support multiple
 * authentication methods and need to prompt the user for a password.
 *
 * Since: 3.0
 */
PURPLE_AVAILABLE_IN_3_0
void purple_connection_set_password(PurpleConnection *connection, const char *password);

/**
 * purple_connection_set_presence:
 * @presence: (transfer none): the saved presence to use
 *
 * Tells the connection to adjust its presence using the given saved presence.
 *
 * It is expected that a protocol may need to ignore some of the saved
 * presence's properties or need to map between primitives.
 *
 * For example, IRC only has offline, available, and away, so invisible would
 * be mapped to offline, where idle, do not disturb, etc would be mapped to
 * away.
 *
 * The implementation should update the [class@Presence] of the
 * [property@Account:contact-info] to reflect the actual presence of the
 * connection.
 *
 * The default implementation will adjust the presence on the account's contact
 * info to match the saved presence meaning if you don't need to report a
 * presence change, you can skip implementing this.
 *
 * Since: 3.0
 */
PURPLE_AVAILABLE_IN_3_0
void purple_connection_set_presence(PurpleConnection *connection, PurpleSavedPresence *presence);

G_END_DECLS

#endif /* PURPLE_CONNECTION_H */

