sml_error.c
/*
* libsyncml - A syncml protocol implementation
* Copyright (C) 2005 Armin Bauer <armin.bauer@opensync.org>
* Copyright (C) 2008-2009 Michael Bell <michael.bell@opensync.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "syncml.h"
#include "syncml_internals.h"
#include "sml_error_internals.h"
const char *smlErrorTypeGetMessage(SmlErrorType type)
{
if (SML_ERROR_UNKNOWN)
return "An unkown error occured.";
/* return NULL if this is not an error */
if (type < 300)
return NULL;
/* Errors according to SyncML Representation Protocol 1.2.1
* The error messages are the original phrases like specified
* by the OMA in the original specifications.
*/
switch (type)
{
/* Retry error */
case SML_ERROR_MULTIPLE_CHOICES:
return "Multiple choices. The requested target is one of a number of " \
"multiple alternatives requested target. The alternative SHOULD " \
"also be returned in the Item element type in the Status.";
case SML_ERROR_MOVED_PERMANENTLY:
return "Moved permanently. The requested target has a new URI. The new " \
"URI SHOULD also be returned in the Item element type in the " \
"Status.";
case SML_ERROR_FOUND_RETRY:
return "Found. The requested target has temporarily moved to a different " \
"URI. The original URI SHOULD continue to be used. The URI of " \
"the temporary location SHOULD also be returned in the Item " \
"element type in the Status. The requestor SHOULD confirm the " \
"identity and authority of the temporary URI to act on behalf of the " \
"original target URI.";
case SML_ERROR_SEE_OTHER_RETRY:
return "See other. The requested target can be found at another URI. The " \
"other URI SHOULD be returned in the Item element type in the " \
"Status.";
case SML_ERROR_NOT_MODIFIED:
return "Not modified. The requested SyncML command was not executed " \
"on the target. This is an additional response that can be added to " \
"any of the other Redirection response codes.";
case SML_ERROR_USE_PROXY:
return "Use proxy. The requested target MUST be accessed through the " \
"specified proxy URI. The proxy URI SHOULD also be returned in " \
"the Item element type in the Status.";
/* Errors */
case SML_ERROR_BAD_REQUEST:
return "Bad request. The requested command could not be performed " \
"because of malformed syntax in the command. The malformed " \
"command MAY also be returned in the Item element type in the " \
"Status.";
case SML_ERROR_AUTH_REJECTED:
return "Invalid credentials. The requested command failed because the " \
"requestor MUST provide proper authentication. If the property type " \
"of authentication was presented in the original request, then the " \
"response code indicates that the requested command has been " \
"refused for those credentials.";
case SML_ERROR_PAYMENT_NEEDED:
return "Paymentneeded. The requested command failed because proper " \
"payment isneeded. This version of SyncML does not standardize " \
"the payment mechanism.";
case SML_ERROR_FORBIDDEN:
return "Forbidden. The requested command failed, but the recipient " \
"understood the requested command. Authentication will not help " \
"and the request SHOULD NOT be repeated. If the recipient wishes " \
"to make public why the request was denied, then a description " \
"MAY be specified in the Item element type in the Status. If the " \
"recipient does not wish to make public why the request was denied " \
"then the response code 404 MAY be used instead.";
case SML_ERROR_NOT_FOUND:
return "Not found. The requested target was not found. No indication is " \
"given as to whether this is a temporary or permanent condition. The " \
"response code 410 SHOULD be used when the condition is " \
"permanent and the recipient wishes to make this fact public. This " \
"response code is also used when the recipient does not want to " \
"make public the reason for why a requested command is not " \
"allowed or when no other response code is appropriate.";
case SML_ERROR_UNSUPPORTED_FEATURE:
return "Optional feature not supported. The requested command failed " \
"because an OPTIONAL feature in the request was not supported. " \
"The unsupported feature SHOULD be specified by the Item " \
"element type in the Status.";
case SML_ERROR_RETRY_LATER:
return "Retry later. The request failed at this time and the originator " \
"SHOULD retry the request later. The recipient SHOULD specify a " \
"RespURI with the response URI and the date/time that the " \
"command SHOULD be repeated.";
case SML_ERROR_ALREADY_EXISTS:
return "Already exists. The requested Put or Add command failed " \
"because the target already exists.";
case SML_ERROR_SIZE_MISMATCH:
return "Size mismatch. The chunked object was received, but the size of " \
"the received object did not match the size declared within the first " \
"chunk.";
/* Standard errors */
case SML_ERROR_GENERIC:
return "Command failed. The recipient encountered an unexpected " \
"condition which prevented it from fulfilling the request.";
case SML_ERROR_NOT_IMPLEMENTED:
return "Command not implemented. The recipient does not support the " \
"command REQUIRED to fulfill the request. This is the appropriate " \
"response when the recipient does not recognize the requested " \
"command and is not capable of supporting it for any resource.";
case SML_ERROR_SERVICE_UNAVAILABLE:
return "Service unavailable. The recipient is currently unable to handle the " \
"request due to a temporary overloading or maintenance of the " \
"recipient. The implication is that this is a temporary condition; " \
"which will be alleviated after some delay. The recipient SHOULD " \
"specify the URI and date/time after which the originator SHOULD " \
"retry in the RespURI in the response.";
case SML_ERROR_REQUIRE_REFRESH:
return "RefreshREQUIRED. An error occurred that necessitates a refresh " \
"of the current synchronization state of the client with the server. " \
"Client is requested to initiate the session type specified in the " \
"server's ALERT (which is included in the same package as the " \
"Status 508). The only valid values for this ALERT are either a slow " \
"sync (201) or a refresh with the server.";
case SML_ERROR_SERVER_FAILURE:
return "Server failure. A severe error occurred in the server while " \
"processing the request. The originator SHOULD NOT retry the " \
"request.";
/* Internal errors */
case SML_ERROR_INTERNAL_IO_ERROR:
return "An internal I/O error occured.";
case SML_ERROR_INTERNAL_TIMEOUT:
return "An internal timeout occured.";
case SML_ERROR_INTERNAL_FILE_NOT_FOUND:
return "An internal error occured because of a missing file.";
case SML_ERROR_INTERNAL_MISCONFIGURATION:
return "An internal misconfiguration was detected.";
case SML_ERROR_INTERNAL_NO_MEMORY:
return "An internal I/O error occured.";
default:
return "";
}
}
void smlErrorSetVargs(SmlError **error, SmlErrorType type, const char *format, va_list args)
{
return_if_fail(error);
return_if_fail(smlErrorIsSet(error) == FALSE);
return_if_fail(format);
*error = (SmlError *) malloc(sizeof(SmlError));
return_if_fail(*error);
(*error)->message = g_strdup_vprintf(format, args);
(*error)->type = type;
const char *msg = smlErrorTypeGetMessage(type);
if (!msg) {
(*error)->printMessage = g_strdup((*error)->message);
} else if (strlen(msg) == 0) {
(*error)->printMessage = g_strdup_printf(
"Error %d: %s",
(*error)->type,
(*error)->message);
} else {
(*error)->printMessage = g_strdup_printf(
"%s %s",
msg,
(*error)->message);
}
(*error)->refCount = 1;
return;
}
SmlError **smlErrorRef(SmlError **error)
{
if (!smlErrorIsSet(error))
return error;
g_atomic_int_inc(&(*error)->refCount);
return error;
}
void smlErrorDeref(SmlError **error)
{
if (!smlErrorIsSet(error))
return;
if (!g_atomic_int_dec_and_test(&((*error)->refCount))) {
*error = NULL;
return;
}
if ((*error)->message)
smlSafeCFree (&((*error)->message));
if ((*error)->printMessage)
smlSafeCFree (&((*error)->printMessage));
smlSafeFree((gpointer *)error);
}
SmlBool smlErrorIsSet(SmlError **error)
{
if (!error)
return FALSE;
if (*error == NULL)
return FALSE;
return TRUE;
}
SmlErrorType smlErrorGetType(SmlError **error)
{
if (!smlErrorIsSet(error))
return SML_NO_ERROR;
return (*error)->type;
}
const char *smlErrorPrint(SmlError **error)
{
if (!smlErrorIsSet(error))
return NULL;
return (*error)->printMessage;
}
void smlErrorUpdate(SmlError **error, const char *format, ...)
{
return_if_fail(smlErrorIsSet(error));
char *old = (*error)->message;
va_list args;
va_start(args, format);
(*error)->message = g_strdup_vprintf(format, args);
va_end (args);
smlSafeCFree(&old);
}
void smlErrorDuplicate(SmlError **target, SmlError **source)
{
return_if_fail(target != NULL);
return_if_fail(smlErrorIsSet(source));
return_if_fail(!smlErrorIsSet(target));
smlErrorSet(target, (*source)->type, (*source)->message);
}
void smlErrorSet(SmlError **error, SmlErrorType type, const char *format, ...)
{
va_list args;
va_start(args, format);
smlErrorSetVargs(error, type, format, args);
va_end (args);
}
void smlErrorSetType(SmlError **error, SmlErrorType type)
{
return_if_fail(error != NULL);
(*error)->type = type;
}
SmlErrorClass smlErrorGetClass(SmlError **error)
{
if (!smlErrorIsSet(error))
return SML_ERRORCLASS_SUCCESS;
if ((*error)->type == SML_NO_ERROR)
return SML_ERRORCLASS_SUCCESS;
return (int)((*error)->type / 100);
}
smlErrorPrint
const char * smlErrorPrint(SmlError **error)
Returns the message of the error.
Definition: sml_error.c:299
smlErrorGetType
SmlErrorType smlErrorGetType(SmlError **error)
Returns the type of the error.
Definition: sml_error.c:285
SmlError::type
SmlErrorType type
Definition: sml_error_internals.h:31
smlErrorUpdate
void smlErrorUpdate(SmlError **error, const char *format,...)
Updates the error message.
Definition: sml_error.c:317
smlErrorTypeGetMessage
const char * smlErrorTypeGetMessage(SmlErrorType type)
Returns a string representation for a SyncML error.
Definition: sml_error.c:47
smlErrorDuplicate
void smlErrorDuplicate(SmlError **target, SmlError **source)
Duplicates the error into the target.
Definition: sml_error.c:337
smlErrorGetClass
SmlErrorClass smlErrorGetClass(SmlError **error)
Gets the error class.
Definition: sml_error.c:382
smlErrorSetVargs
void smlErrorSetVargs(SmlError **error, SmlErrorType type, const char *format, va_list args)
Sets a error from a va_list.
Definition: sml_error.c:194
smlErrorIsSet
SmlBool smlErrorIsSet(SmlError **error)
Checks if the error is set.
Definition: sml_error.c:268
smlErrorSetType
void smlErrorSetType(SmlError **error, SmlErrorType type)
Sets the type of an error.
Definition: sml_error.c:369
smlErrorSet
void smlErrorSet(SmlError **error, SmlErrorType type, const char *format,...)
Sets the error.
Definition: sml_error.c:355
SmlError
Represent an error.
Definition: sml_error_internals.h:29