<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -2,11 +2,14 @@
 #include &quot;communication.h&quot;
 #include &quot;album.h&quot;
 
+#define GET_INFO_METHOD_NAME &quot;album.getInfo&quot;
+
 static lfmmethod const album_method_declarations[] =
 {
-	{&quot;album.addTags&quot;,   POST_METHOD, {{&quot;tags&quot;, utf8_array2csl, FALSE}}},
-    {&quot;album.getInfo&quot;,   GET_METHOD,  {{&quot;mbid&quot;, NULL, TRUE}}},
-    {&quot;album.removeTag&quot;, POST_METHOD, {{&quot;tag&quot;, NULL, FALSE}}}
+	//method name          type         //parameter                                 
+	{&quot;album.addTags&quot;,      POST_METHOD, {{&quot;artist&quot;}, {&quot;album&quot;}, {&quot;tags&quot;, utf8_array2csl}} },
+    {GET_INFO_METHOD_NAME, GET_METHOD,  {{&quot;artist&quot;}, {&quot;album&quot;}                          } },
+    {&quot;album.removeTag&quot;,    POST_METHOD, {{&quot;artist&quot;}, {&quot;album&quot;}, {&quot;tag&quot;}                 } }
 };
 
 //enum has to be index of declarations
@@ -15,13 +18,21 @@ enum album_methods
 {
 	add_tags,
 	get_info,
-	removeTag
+	remove_tag
+};
+
+static lfmmethod mbid_method =
+{
+	GET_INFO_METHOD_NAME,
+	GET_METHOD,
+	{{&quot;mbid&quot;}}	
 };
 
 static const lfmget primary_methods[] = 
 {
-	{&amp;album_method_declarations[get_info], {&quot;album&quot;, &quot;name&quot;}, DATA_UTF8},
-	{&amp;album_method_declarations[get_info], {&quot;album&quot;, &quot;artist&quot;}, DATA_UTF8},
+	//method                               //path to data     data type
+	{&amp;mbid_method,                         {&quot;album&quot;, &quot;name&quot;}, DATA_UTF8},
+	{&amp;mbid_method,                         {&quot;album&quot;, &quot;artist&quot;}, DATA_UTF8},
 	{&amp;album_method_declarations[get_info], {&quot;album&quot;, &quot;mbid&quot;}, DATA_UTF8},
 	{&amp;album_method_declarations[get_info], {&quot;album&quot;, &quot;url&quot;}, DATA_URL},
 	{&amp;album_method_declarations[get_info], {&quot;album&quot;, &quot;releasedate&quot;}, DATA_URL},
@@ -48,37 +59,28 @@ enum primary_info
 
 static const lfmget related_methods[] = 
 {
-	{&amp;album_method_declarations[get_info], {&quot;album&quot;, &quot;toptags&quot;, &quot;tag&quot;, &quot;name&quot;}, DATA_UTF8}	
+	{&amp;album_method_declarations[get_info], {&quot;album&quot;, &quot;toptags&quot;, &quot;tag&quot;, &quot;name&quot;}, DATA_UTF8},
+	{&amp;album_method_declarations[add_tags], {}, DATA_VOID},
+	{&amp;album_method_declarations[remove_tag], {}, DATA_VOID},
 };
 
 enum related_info
 {
-	ALBUM_TOP_TAGS
+	ALBUM_TOP_TAGS,
+	ALBUM_ADD_TAGS,
+	ALBUM_REMOVE_TAG
 };
 
+#define album_call_method_with_parameters(artist, album, call, callback, user_data, ...) \
+	call_method_with_parameters(call, callback, user_data, artist, album, __VA_ARGS__);
+
 void album_get_info(const gchar* artist, const gchar* album, const lfmget* call, gpointer callback, gpointer user_data)
-{	
-	createv(lfmparametervalue, parameters);
-	
-	//add artist parameter	
-	lfmparametervalue* para = g_new(lfmparametervalue, 1);
-	para-&gt;name = &quot;artist&quot;;
-	para-&gt;value = artist;
-	addv(lfmparametervalue, parameters, para);
-	
-	//add album parameter
-	para = g_new(lfmparametervalue, 1);
-	para-&gt;name = &quot;album&quot;;
-	para-&gt;value = album;
-	addv(lfmparametervalue, parameters, para);
-	
-	call_method(call, parameters, callback, user_data);
-	
-	destroyv(lfmparametervalue, parameters);
+{
+	album_call_method_with_parameters(artist, album, call, callback, user_data, NULL);
 }
 
 void album_get_name(const gchar* musicbrainz_id, utf8_callback callback, gpointer user_data)
-{
+{	
 	call_method_with_parameters(&amp;primary_methods[ALBUM_NAME], callback, user_data, musicbrainz_id, NULL);
 }
 
@@ -140,3 +142,13 @@ void album_get_top_tags(const gchar* artist, const gchar* album, tags_callback c
 {
 	album_get_info(artist, album, &amp;related_methods[ALBUM_TOP_TAGS], callback, user_data);
 }
+
+void album_add_tags(const gchar* artist, const gchar* album, const gchar** tags, void_callback callback, gpointer user_data)
+{	
+	album_call_method_with_parameters(artist, album, &amp;related_methods[ALBUM_ADD_TAGS], callback, user_data, tags, NULL); 
+}
+
+void album_remove_tag(const gchar* artist, const gchar* album, const gchar* tag, void_callback callback, gpointer user_data)
+{
+	album_call_method_with_parameters(artist, album, &amp;related_methods[ALBUM_REMOVE_TAG], callback, user_data, tag, NULL);
+}</diff>
      <filename>album.c</filename>
    </modified>
    <modified>
      <diff>@@ -2,24 +2,22 @@
 #include &quot;communication.h&quot;
 #include &quot;artist.h&quot;
 
-gchar* utf8_copy(gpointer data)
-{
-	return g_strdup(data);
-}
+#define GET_INFO_METHOD_NAME &quot;artist.getInfo&quot;
 
 static const lfmmethod artist_method_declarations[] =
 {
-	{&quot;artist.addTags&quot;,      POST_METHOD, {{&quot;tags&quot;, utf8_array2csl, FALSE}}},
-    {&quot;artist.getEvents&quot;,    GET_METHOD},
-    {&quot;artist.getInfo&quot;,      GET_METHOD,  {{&quot;mbid&quot;, utf8_copy, TRUE}}},
-    {&quot;artist.getSimilar&quot;,   GET_METHOD,  {{&quot;limit&quot;, uint2utf8, TRUE}}},
-    {&quot;artist.getTopAlbums&quot;, GET_METHOD}, 
-    {&quot;artist.getTopFans&quot;,   GET_METHOD},
-    {&quot;artist.getTopTags&quot;,   GET_METHOD},
-    {&quot;artist.getTopTracks&quot;, GET_METHOD},
-    {&quot;artist.removeTag&quot;,    POST_METHOD, {{&quot;tag&quot;, utf8_copy, FALSE}}},
-    {&quot;artist.search&quot;,       GET_METHOD,  {{&quot;limit&quot;, uint2utf8, TRUE}, {&quot;page&quot;, uint2utf8, TRUE}}},
-    {&quot;artist.share&quot;,        POST_METHOD, {{&quot;recipient&quot;, utf8_array2csl, FALSE}, {&quot;message&quot;, NULL, TRUE}}}
+	//method name           type         parameter                                     optional parameter 
+	{&quot;artist.addTags&quot;,      POST_METHOD, {{&quot;artist&quot;}, {&quot;tags&quot;, utf8_array2csl}      }, {                                          } },
+    {&quot;artist.getEvents&quot;,    GET_METHOD,  {{&quot;artist&quot;}                                }, {                                          } },
+    {GET_INFO_METHOD_NAME,  GET_METHOD,  {{&quot;artist&quot;}                                }, {                                          } },
+    {&quot;artist.getSimilar&quot;,   GET_METHOD,  {{&quot;artist&quot;}                                }, {{&quot;limit&quot;, uint2utf8}                      } },
+    {&quot;artist.getTopAlbums&quot;, GET_METHOD,  {{&quot;artist&quot;}                                }, {                                          } }, 
+    {&quot;artist.getTopFans&quot;,   GET_METHOD,  {{&quot;artist&quot;}                                }, {                                          } },
+    {&quot;artist.getTopTags&quot;,   GET_METHOD,  {{&quot;artist&quot;}                                }, {                                          } },
+    {&quot;artist.getTopTracks&quot;, GET_METHOD,  {{&quot;artist&quot;}                                }, {                                          } },
+    {&quot;artist.removeTag&quot;,    POST_METHOD, {{&quot;artist&quot;}, {&quot;tag&quot;}                       }, {                                          } },
+    {&quot;artist.search&quot;,       GET_METHOD,  {{&quot;artist&quot;}                                }, {{&quot;limit&quot;, uint2utf8}, {&quot;page&quot;, uint2utf8} } },
+    {&quot;artist.share&quot;,        POST_METHOD, {{&quot;artist&quot;}, {&quot;recipient&quot;, utf8_array2csl} }, {{&quot;message&quot;}                               } }
 };
 
 //enum has to be index of declarations
@@ -39,9 +37,20 @@ enum artist_methods
 	share
 };
 
+static lfmmethod mbid_method =
+{
+	GET_INFO_METHOD_NAME,
+	GET_METHOD,
+	{{&quot;mbid&quot;}},
+	{}
+};
+
+#undef GET_INFO_METHOD_NAME
+
 static const lfmget primary_methods[] = 
 {
-	{&amp;artist_method_declarations[get_info], {&quot;artist&quot;, &quot;name&quot;}, DATA_UTF8},
+	//method                                path to data        data type 
+	{&amp;mbid_method,                          {&quot;artist&quot;, &quot;name&quot;}, DATA_UTF8},
 	{&amp;artist_method_declarations[get_info], {&quot;artist&quot;, &quot;mbid&quot;}, DATA_UTF8},
 	{&amp;artist_method_declarations[get_info], {&quot;artist&quot;, &quot;url&quot;}, DATA_URL},
 	{&amp;artist_method_declarations[get_info], {&quot;artist&quot;, &quot;image[size=small]&quot;}, DATA_URL},
@@ -52,9 +61,7 @@ static const lfmget primary_methods[] =
 	{&amp;artist_method_declarations[get_info], {&quot;artist&quot;, &quot;stats&quot;, &quot;plays&quot;}, DATA_UINT},
 	{&amp;artist_method_declarations[get_info], {&quot;artist&quot;, &quot;bio&quot;, &quot;published&quot;}, DATA_DATE_TIME},
 	{&amp;artist_method_declarations[get_info], {&quot;artist&quot;, &quot;bio&quot;, &quot;summary&quot;}, DATA_UTF8},
-	{&amp;artist_method_declarations[get_info], {&quot;artist&quot;, &quot;bio&quot;, &quot;content&quot;}, DATA_UTF8},
-	{&amp;artist_method_declarations[add_tags], {}, DATA_VOID},
-	{&amp;artist_method_declarations[remove_tag], {}, DATA_VOID}	
+	{&amp;artist_method_declarations[get_info], {&quot;artist&quot;, &quot;bio&quot;, &quot;content&quot;}, DATA_UTF8}	
 };
 
 enum primary_info
@@ -70,9 +77,7 @@ enum primary_info
 	ARTIST_PLAY_COUNT,
 	ARTIST_TEXT_PUBLISHED,
 	ARTIST_SUMMARY,
-	ARTIST_DESCRIPTION,
-	ARTIST_ADD_TAGS,
-	ARTIST_REMOVE_TAG
+	ARTIST_DESCRIPTION
 };
 
 lfmget related_methods[] =
@@ -84,7 +89,9 @@ lfmget related_methods[] =
 	{&amp;artist_method_declarations[get_top_albums],      {&quot;topalbums&quot;, &quot;album&quot;}, DATA_UTF8},
 	{&amp;artist_method_declarations[get_top_fans],        {&quot;topfans&quot;, &quot;user&quot;, &quot;name&quot;}, DATA_UTF8},
 	{&amp;artist_method_declarations[get_top_tags],        {&quot;toptags&quot;, &quot;tag&quot;, &quot;name&quot;}, DATA_UTF8},
-	{&amp;artist_method_declarations[get_top_tracks],      {&quot;toptracks&quot;, &quot;track&quot;, &quot;name&quot;}, DATA_UTF8}
+	{&amp;artist_method_declarations[get_top_tracks],      {&quot;toptracks&quot;, &quot;track&quot;, &quot;name&quot;}, DATA_UTF8},
+	{&amp;artist_method_declarations[add_tags],            {}, DATA_VOID},
+	{&amp;artist_method_declarations[remove_tag],          {}, DATA_VOID}
 };
 
 enum related_info
@@ -96,28 +103,13 @@ enum related_info
 	ARTIST_TOP_ALBUMS,
 	ARTIST_TOP_FANS,
 	ARTIST_TOP_TAGS,
-	ARTIST_TOP_TRACKS
+	ARTIST_TOP_TRACKS,
+	ARTIST_ADD_TAGS,
+	ARTIST_REMOVE_TAG
 };
 
-G_GNUC_NULL_TERMINATED void artist_call_method_with_parameters(const gchar* artist, const lfmget* call, gpointer callback, gpointer user_data, ...)
-{	
-	createv(lfmparametervalue, parameters);
-		
-	lfmparametervalue* para = g_new(lfmparametervalue, 1);
-	para-&gt;name = &quot;artist&quot;;
-	para-&gt;value = artist;
-	addv(lfmparametervalue, parameters, para);
-	
-	va_list vl;
-	va_start(vl, user_data);
-	
-	fill_parameters(parameters, call-&gt;method, &amp;vl);
-	
-	call_method(call, parameters, callback, user_data);
-	
-	va_end(vl);
-	destroyv(lfmparametervalue, parameters);
-}
+#define artist_call_method_with_parameters(artist, call, callback, user_data, ...) \
+	call_method_with_parameters(call, callback, user_data, artist, __VA_ARGS__);
 
 void artist_get_info(const gchar* artist, const lfmget* call, gpointer callback, gpointer user_data)
 {
@@ -131,16 +123,31 @@ void artist_get_name(const gchar* musicbrainz_id, utf8_callback callback, gpoint
 	call_method_with_parameters(&amp;primary_methods[ARTIST_NAME], callback, user_data, musicbrainz_id, NULL);
 }
 
+gchar* s_artist_get_name(const gchar* musicbrainz_id, GError** error)
+{
+	IMPLEMENT_SYNC_UTF8(artist_get_name, musicbrainz_id);
+}
+
 void artist_get_musicbrainz_id(const gchar* artist, utf8_callback callback, gpointer user_data)
 {
 	artist_get_info(artist, &amp;primary_methods[ARTIST_MUSICBRAINZ_ID], callback, user_data);
 }
 
+gchar* s_artist_get_musicbrainz_id(const gchar* artist, GError** error)
+{
+	IMPLEMENT_SYNC_UTF8(artist_get_musicbrainz_id, artist);
+}
+
 void artist_get_url(const gchar* artist, url_callback callback, gpointer user_data)
 {
 	artist_get_info(artist, &amp;primary_methods[ARTIST_URL], callback, user_data);
 }
 
+gchar* s_artist_get_url(const gchar* artist, GError** error)
+{
+	IMPLEMENT_SYNC_UTF8(artist_get_url, artist);
+}
+
 void artist_get_image_url(const gchar* artist, image_size size, url_callback callback, gpointer user_data)
 {
 	const lfmget* call;
@@ -161,6 +168,11 @@ void artist_get_image_url(const gchar* artist, image_size size, url_callback cal
 	artist_get_info(artist, call, callback, user_data);
 }
 
+gchar* s_artist_get_image_url(const gchar* artist, image_size size, GError** error)
+{
+	IMPLEMENT_SYNC_UTF8(artist_get_image_url, artist, size);
+}
+
 void artist_is_streamable(const gchar* artist, boolean_callback callback, gpointer user_data)
 {
 	artist_get_info(artist, &amp;primary_methods[ARTIST_STREAMABLE], callback, user_data);
@@ -191,16 +203,6 @@ void artist_get_description(const gchar* artist, utf8_callback callback, gpointe
 	artist_get_info(artist, &amp;primary_methods[ARTIST_DESCRIPTION], callback, user_data);	
 }
 
-void artist_add_tags(const gchar* artist, const gchar** tags, void_callback callback, gpointer user_data)
-{	
-	artist_call_method_with_parameters(artist, &amp;primary_methods[ARTIST_ADD_TAGS], callback, user_data, tags, NULL); 
-}
-
-void artist_remove_tag(const gchar* artist, const gchar* tag, void_callback callback, gpointer user_data)
-{
-	artist_call_method_with_parameters(artist, &amp;primary_methods[ARTIST_REMOVE_TAG], callback, user_data, tag, NULL);
-}
-
 //
 //Related information
 //
@@ -241,6 +243,16 @@ void artist_get_top_tracks(const gchar* artist, tracks_callback callback, gpoint
 	artist_get_info(artist, &amp;related_methods[ARTIST_TOP_TRACKS], callback, user_data);
 }
 
+void artist_add_tags(const gchar* artist, const gchar** tags, void_callback callback, gpointer user_data)
+{	
+	artist_call_method_with_parameters(artist, &amp;related_methods[ARTIST_ADD_TAGS], callback, user_data, tags, NULL); 
+}
+
+void artist_remove_tag(const gchar* artist, const gchar* tag, void_callback callback, gpointer user_data)
+{
+	artist_call_method_with_parameters(artist, &amp;related_methods[ARTIST_REMOVE_TAG], callback, user_data, tag, NULL);
+}
+
 /*
     * artist.search
     * artist.share</diff>
      <filename>artist.c</filename>
    </modified>
    <modified>
      <diff>@@ -14,6 +14,7 @@ typedef enum image_size image_size;
 //Primary artist information
 //
 
+//Asynchronous calls
 void artist_get_name(const gchar* musicbrainz_id, utf8_callback callback, gpointer user_data);
 void artist_get_musicbrainz_id(const gchar* artist, utf8_callback callback, gpointer user_data);
 void artist_get_url(const gchar* artist, url_callback callback, gpointer user_data);
@@ -24,13 +25,25 @@ void artist_get_play_count(const gchar* artist, uint_callback callback, gpointer
 void artist_get_published_date_time(const gchar* artist, date_time_callback callback, gpointer user_data);
 void artist_get_summary(const gchar* artist, utf8_callback callback, gpointer user_data);
 void artist_get_description(const gchar* artist, utf8_callback callback, gpointer user_data);
-void artist_add_tags(const gchar* artist, const gchar** tags, void_callback callback, gpointer user_data);
-void artist_remove_tag(const gchar* artist, const gchar* tag, void_callback callback, gpointer user_data);
+
+//Synchronous calls
+gchar* s_artist_get_name(const gchar* musicbrainz_id, GError** error);
+gchar* s_artist_get_musicbrainz_id(const gchar* artist, GError** error);
+gchar* s_artist_get_url(const gchar* artist, GError** error);
+gchar* s_artist_get_image_url(const gchar* artist, image_size size, GError** error);
+gboolean s_artist_is_streamable(const gchar* artist, GError** error);
+guint s_artist_get_listener_count(const gchar* artist, GError** error);
+guint s_artist_get_play_count(const gchar* artist, GError** error);
+struct tm s_artist_get_published_date_time(const gchar* artist, GError** error);
+gchar* s_artist_get_summary(const gchar* artist, GError** error);
+gchar* s_artist_get_description(const gchar* artist, GError** error);
 
 //
 //Related information
 //
 
+void artist_add_tags(const gchar* artist, const gchar** tags, void_callback callback, gpointer user_data);
+void artist_remove_tag(const gchar* artist, const gchar* tag, void_callback callback, gpointer user_data);
 void artist_get_events(const gchar* artist, events_callback callback, gpointer user_data);
 //0 means no limit
 void artist_get_similar_artists(const gchar* artist, guint limit, artists_callback callback, gpointer user_data);</diff>
      <filename>artist.h</filename>
    </modified>
    <modified>
      <diff>@@ -6,7 +6,8 @@
 
 const lfmmethod authentication_method_declarations[] = 
 {
-	{&quot;auth.getToken&quot;, GET_METHOD, {}, {{TOKEN_NOT_GRANTED, &quot;There was an error granting the request token. Please try again later.&quot;},{0, NULL}}}
+	//method name     type        parameter  optional parameter  specific errors
+	{&quot;auth.getToken&quot;, GET_METHOD, {},        {},                 {{TOKEN_NOT_GRANTED, &quot;There was an error granting the request token. Please try again later.&quot;},{0, NULL}}}
 };
 
 //enum has to be index of declarations
@@ -31,6 +32,24 @@ void authentication_get_token(utf8_callback callback, gpointer user_data)
 	call_method_with_parameters(&amp;primary_methods[AUTHENTICATION_GET_TOKEN], callback, user_data, NULL);
 }
 
+gchar* s_authentication_get_token(GError** error)
+{
+	struct utf8_syncer syncer;
+	syncer.string = NULL;
+	syncer.error = NULL;
+	syncer.signal = g_cond_new();
+	authentication_get_token(utf8_sync, &amp;syncer);
+	GMutex* mutex = g_mutex_new();
+	g_cond_wait(syncer.signal, mutex);
+	g_mutex_free(mutex);
+	if(syncer.error)
+	{
+		*error = syncer.error;
+		return NULL;
+	}
+	return syncer.string;
+}
+
 struct authenticate_data
 {
 	boolean_callback callback;</diff>
      <filename>authentication.c</filename>
    </modified>
    <modified>
      <diff>@@ -6,5 +6,6 @@
 
 void authenticate(gpointer user_data);
 void authentication_get_token(utf8_callback callback, gpointer user_data);
+gchar* s_authentication_get_token(GError** error);
 
 #endif /*AUTHENTICATION_H_*/</diff>
      <filename>authentication.h</filename>
    </modified>
    <modified>
      <diff>@@ -1,9 +1,10 @@
 #ifndef CALLBACK_H_
 #define CALLBACK_H_
 
-#include &lt;glib.h&gt;
-#define _XOPEN_SOURCE //glibc2 needs this
+#define _XOPEN_SOURCE
 #include &lt;time.h&gt;
+#include &lt;glib.h&gt;
+//#define _XOPEN_SOURCE //glibc2 needs this
 
 enum error_codes
 {</diff>
      <filename>callback.h</filename>
    </modified>
    <modified>
      <diff>@@ -2,19 +2,39 @@
 #include &lt;gcrypt.h&gt;
 #include &lt;curl/curl.h&gt;
 #include &quot;include.h&quot;
-#include &quot;proxy.h&quot; 
+#include &quot;proxy.h&quot;
+#include &quot;authentication.h&quot;
 #include &quot;communication.h&quot;
 
 #define API_KEY &quot;100780b228c8aa69be51d709572b45b8&quot;
 #define SECRET &quot;ba296e6c0de47df63b43d4410a702626&quot;
 #define WEBSERVICE_URL &quot;http://ws.audioscrobbler.com/2.0/&quot;
 #define METHOD_KEY &quot;method&quot;
-#define METHOD_PARAMETER &quot;?&quot;METHOD_KEY&quot;=&quot;;
-static const char METHOD_URL[] = WEBSERVICE_URL&quot;&quot;METHOD_PARAMETER;
+static const char GET_URL[] = WEBSERVICE_URL&quot;?&quot;;
 
-#define API_PARAMETER &quot;&amp;api_key=&quot;API_KEY
+#define API_PARAMETER &quot;api_key&quot;
 static const char API_PARAMETER_ARRAY[] = API_PARAMETER;
 
+IMPLEMENT_PRINT_FUNCTIONS(communication, &quot;Communication&quot;)
+
+struct lfmparametervalue
+{
+	const gchar* name;
+	const gchar* value;
+};
+
+typedef struct lfmparametervalue lfmparametervalue;
+
+void utf8_sync(const gchar* string, gpointer user_data, GError* error)
+{
+	struct utf8_syncer* syncer = user_data;
+	syncer-&gt;string = g_strdup(string);
+	syncer-&gt;error = error;
+	
+	//we are ready to get back to the synced version
+	g_cond_signal(syncer-&gt;signal);
+}
+
 size_t sum_uintv(guint* array)
 {
 	guint* uint_iterator = array;
@@ -29,14 +49,11 @@ size_t sum_uintv(guint* array)
 	return text_len;
 }
 
-gchar* build_url(CURL* handle, const gchar* method_name, const lfmparametervalue** values)
+gchar* build_url(CURL* handle, lfmparametervalue** values)
 {
-	const lfmparametervalue** iterator = values;
-	guint length = G_N_ELEMENTS(METHOD_URL);
-	guint method_length = g_utf8_strlen(method_name, -1);
-	length += method_length;
-	length += G_N_ELEMENTS(API_PARAMETER);
-	
+	lfmparametervalue* const * iterator = values;
+	guint length = G_N_ELEMENTS(GET_URL);
+		
 	createv(char, escaped_names);
 	createv(char, escaped_values);
 		
@@ -56,12 +73,8 @@ gchar* build_url(CURL* handle, const gchar* method_name, const lfmparametervalue
 	gchar* current = url;
 	
 	//add method url
-	current = g_stpcpy(current, METHOD_URL);
-	current = g_stpcpy(current, method_name);
-		
-	//add api key
-	current = g_stpcpy(current, API_PARAMETER);
-		
+	current = g_stpcpy(current, GET_URL);
+	
 	iterator = values;
 	
 	char** name_iterator = escaped_names;
@@ -95,9 +108,9 @@ gchar* build_url(CURL* handle, const gchar* method_name, const lfmparametervalue
 	return url;
 }
 
-gchar* build_request_url(CURL* handle, const gchar* method_name, const lfmparametervalue** values)
+gchar* build_request_url(CURL* handle, lfmparametervalue** values)
 {
-	return build_url(handle, method_name, values); 
+	return build_url(handle, values); 
 }
 
 gchar* build_post_url()
@@ -112,7 +125,8 @@ EMBED_PRINT_FUNCTIONS(token, &quot;Token&quot;)
 
 const lfmmethod token_method_declarations[] = 
 {
-	{&quot;auth.getSession&quot;, GET_METHOD, {{&quot;token&quot;, NULL, FALSE}}, {{AUTHENTICATION_FAILED, &quot;Invalid authentication token supplied&quot;},{TOKEN_UNAUTHORIZED, &quot;This token has not been authorized&quot;},{TOKEN_EXPIRED, &quot;This token has expired&quot;},{0, NULL}}}
+	//method name       tpye        parameter          optional parameter  specific errors
+	{&quot;auth.getSession&quot;, GET_METHOD, {{&quot;token&quot;, NULL}}, {},                 {{AUTHENTICATION_FAILED, &quot;Invalid authentication token supplied&quot;},{TOKEN_UNAUTHORIZED, &quot;This token has not been authorized&quot;},{TOKEN_EXPIRED, &quot;This token has expired&quot;},{0, NULL}}}
 };
 
 enum token_method
@@ -134,21 +148,6 @@ enum token_data
 	SESSION_IS_SUBSCRIBER
 };
 
-void session_get_name(const gchar* token, utf8_callback callback, gpointer user_data)
-{
-	call_method_with_parameters(&amp;token_data_declarations[SESSION_NAME], callback, user_data, token, NULL); 
-}
-
-void session_get_key(const gchar* token, utf8_callback callback, gpointer user_data)
-{
-	call_method_with_parameters(&amp;token_data_declarations[SESSION_KEY], callback, user_data, token, NULL);
-}
-
-void session_is_subscriber(const gchar* token, boolean_callback callback, gpointer user_data)
-{
-	call_method_with_parameters(&amp;token_data_declarations[SESSION_IS_SUBSCRIBER], callback, user_data, token, NULL);
-}	
-
 void token_request_authorization(const gchar* token)
 {
 	createv(gchar, argv);
@@ -182,34 +181,110 @@ void token_request_authorization(const gchar* token)
 	g_free(argv);
 }
 
-const gchar* token_get_session(const gchar* token)
+struct lfmsession
+{
+	gchar* name;
+	gchar* key;
+	gboolean subscriber;	
+};
+
+typedef struct lfmsession lfmsession;
+
+typedef void (*lfmsession_callback)(const lfmsession* session, gpointer user_data, GError* error);
+
+void token_create_session(const gchar* token, lfmsession_callback callback, gpointer user_data)
 {
-/*
-	get_data_from_method(&quot;auth.getSession&quot;, 
-	token:
-	api_sig: token_get_signature(token, auth.getsession);
 	
-	*  2 : Invalid service -This service does not exist
-    * 3 : Invalid Method - No method with that name in this package
-    * 4 : Authentication Failed - You do not have permissions to access the service
-    * 5 : Invalid format - This service doesn't exist in that format
-    * 6 : Invalid parameters - Your request is missing a required parameter
-    * 7 : Invalid resource specified
-    * 9 : Invalid session key - Please re-authenticate
-    * 10 : Invalid API key - You must be granted a valid key by last.fm
-    * 11 : Service Offline - This service is temporarily offline. Try again later.
-    * 12 : Subscribers Only - This service is only available to paid last.fm subscribers
-    * 4 : Invalid authentication token supplied
-    * 14 : This token has not been authorized
-    * 15 : This token has expired
-*/
 }
 
-void token_get_signature(const gchar* token, const gchar* method_name)
+struct session_syncer
 {
-	gchar* string = g_strdup_printf(&quot;api_key&quot;API_KEY&quot;token%s&quot;METHOD_KEY&quot;%s&quot;SECRET, token, method_name);
-	//gchar* signature = md5();
-	g_free(string);
+	lfmsession* session;
+	GError* error;
+	GCond* signal;
+};
+
+lfmsession* session_deep_copy(const lfmsession* session)
+{
+	lfmsession* psession = g_memdup(session, sizeof(lfmsession));
+	psession-&gt;name = g_strdup(session-&gt;name);
+	psession-&gt;key = g_strdup(session-&gt;key);
+	return psession;
+}
+
+void session_sync(const lfmsession* session, gpointer user_data, GError* error)
+{
+	struct session_syncer* syncer = user_data;
+	syncer-&gt;session = session_deep_copy(session);
+	syncer-&gt;error = error;
+	
+	//we are ready to get back to the synced version
+	g_cond_signal(syncer-&gt;signal);
+}
+
+lfmsession* s_token_create_session(const gchar* token, GError** error)
+{
+	struct session_syncer syncer;
+	syncer.session = NULL;
+	syncer.error = NULL;
+	syncer.signal = g_cond_new();
+	token_create_session(token, session_sync, &amp;syncer);
+	g_cond_wait(syncer.signal, NULL);
+	if(syncer.error)
+	{
+		*error = syncer.error;
+		return NULL;
+	}
+	return syncer.session;
+}
+
+gboolean collect_parameter(gpointer key, gpointer value, gpointer data)
+{
+	const lfmparametervalue* parameter = value;
+	gchar** buffer = data;
+	
+	*buffer = g_stpcpy(*buffer, parameter-&gt;name);
+	*buffer = g_stpcpy(*buffer, parameter-&gt;value);
+	
+	return FALSE;	
+}
+
+gchar* get_parameter_signature(const lfmget* call, lfmparametervalue** parameters)
+{
+	GTree* sortTree = g_tree_new((GCompareFunc)strcmp);
+	
+	lfmparametervalue* const * iterator = parameters;
+	size_t size = 0;
+	
+	//add all paramters to tree so they are automaticly sorted
+	while(*iterator)
+	{
+		size += strlen((*iterator)-&gt;name);
+		size += strlen((*iterator)-&gt;value);
+		
+		//casting to gpointer to eliminate warning
+		//be cautious that any action on the tree must not modify the parameter
+		g_tree_insert(sortTree, (gpointer)(*iterator)-&gt;name, (gpointer)*iterator);
+		iterator++;
+	}
+	
+	//we have to add the secret
+	size += strlen(SECRET);
+	
+	gchar* buffer = g_new(gchar, size);
+	gchar* current_buffer = buffer;
+	
+	g_tree_foreach(sortTree, collect_parameter, &amp;current_buffer);
+	
+	//add the secret
+	current_buffer = g_stpcpy(current_buffer, SECRET);
+	
+	//create md5 checksum
+	gchar* md5 = g_compute_checksum_for_string(G_CHECKSUM_MD5, buffer, size);
+	
+	g_free(buffer);
+	
+	return md5;
 }
 
 //
@@ -448,6 +523,11 @@ void invoke_callback(enum data_type type, const gchar* text, gpointer callback,
 			((uint_callback)callback)(result, user_data, error);
 			break;
 		}
+		case DATA_VOID:
+		{
+			((void_callback)callback)(user_data, error);
+			break;
+		}
 		default: //DATA_UTF8 OR DATA_URL
 		{
 			((utf8_callback)callback)(text, user_data, error);
@@ -768,11 +848,11 @@ struct xml_parser* init_parser(const lfmget* call, gpointer callback, gpointer u
 	return parser;	
 }
 
-void proxy_request(lfmproxy* proxy, const lfmget* call, const lfmparametervalue** parameters, gpointer callback, gpointer user_data)
+void proxy_request(lfmproxy* proxy, const lfmget* call, lfmparametervalue*** parameters, gpointer callback, gpointer user_data)
 {
 	CURL* easy_handle = curl_easy_init();
 	
-	gchar* url = build_request_url(easy_handle, call-&gt;method-&gt;name, parameters);
+	gchar* url = build_request_url(easy_handle, *parameters);
 	CURLcode code = curl_easy_setopt(easy_handle, CURLOPT_URL, url);	
 	g_free(url);
 	
@@ -806,21 +886,106 @@ void cleanup_post(gpointer data, gpointer user_data)
 	curl_formfree(post);
 }
 
-void proxy_post(lfmproxy* proxy, const lfmget* call, const lfmparametervalue** parameters, gpointer callback, gpointer user_data)
+#define METHOD_SIGNATURE_PARAMETER_NAME &quot;api_sig&quot;
+#define SESSION_KEY_PARAMETER_NAME &quot;sk&quot;
+
+GStaticMutex session_mutex = G_STATIC_MUTEX_INIT;
+static lfmsession* the_session = NULL;
+
+lfmsession* get_lfm_session(GError** error)
+{
+	g_static_mutex_lock(&amp;session_mutex);
+			
+	if(the_session)
+	{
+		g_static_mutex_unlock(&amp;session_mutex);
+		return the_session;
+	}	
+	
+	gchar* token = s_authentication_get_token(error);
+		
+	if(*error)
+	{
+		communication_printerr((*error)-&gt;message);
+		g_static_mutex_unlock(&amp;session_mutex);
+		return NULL;
+	}
+	
+	//no other thread did already get the session
+	the_session = s_token_create_session(token, error);
+	
+	if(*error)
+	{
+		//app needs to be authenticated first
+		if((*error)-&gt;code == 9)
+		{
+			token_request_authorization(token);
+		}
+					
+		communication_printerr((*error)-&gt;message);
+		g_static_mutex_unlock(&amp;session_mutex);
+		return NULL;
+	}
+	
+	g_free(token);
+	
+	g_static_mutex_unlock(&amp;session_mutex);
+	
+	return the_session;
+}
+
+void proxy_post(lfmproxy* proxy, const lfmget* call, lfmparametervalue*** parameters, gpointer callback, gpointer user_data)
 {	
+	GError* error = NULL;
+	lfmsession* session = get_lfm_session(&amp;error);
+	
+	if(error)
+	{
+		invoke_callback(call-&gt;data_parser, NULL, callback, user_data, error);
+		return;
+	}		
+	
+	//
+	//Add parameters
+	//
+		
+	//Add session key
+	lfmparametervalue* parameter = g_new0(lfmparametervalue, 2);
+	parameter-&gt;name = SESSION_KEY_PARAMETER_NAME;
+	parameter-&gt;value = session-&gt;key;
+	addv(lfmparametervalue, *parameters, parameter);
+	
+	//Sign parameters
+	gchar* signature = get_parameter_signature(call, *parameters);
+		
+	parameter++;
+	
+	parameter-&gt;name = &quot;api_sig&quot;;
+	parameter-&gt;value = signature;
+	addv(lfmparametervalue, *parameters, parameter);
+	
 	struct curl_httppost* post = NULL;
 	struct curl_httppost* last = NULL;
 	
 	CURLFORMcode code = curl_formadd(&amp;post, &amp;last, CURLFORM_COPYNAME, METHOD_KEY, CURLFORM_COPYCONTENTS, call-&gt;method-&gt;name, CURLFORM_END);
 
-	const lfmparametervalue** iterator = parameters;
+	lfmparametervalue* const * iterator = *parameters;
+	size_t count = 0;
 	
 	while(*iterator)
 	{	
 		code = curl_formadd(&amp;post, &amp;last, CURLFORM_COPYNAME, (*iterator)-&gt;name, CURLFORM_COPYCONTENTS, (*iterator)-&gt;value, CURLFORM_END);
+		count++;
 		iterator++;
 	}
 	
+	g_free(signature);
+	
+	//cleanup all in this function added parameters
+	(*parameters)[count - 1] = NULL;
+	(*parameters)[count - 2] = NULL;
+	g_free(--parameter);
+	
 	CURL* easy_handle = curl_easy_init();
 	code = curl_easy_setopt(easy_handle, CURLOPT_HTTPPOST, post);
 	
@@ -856,7 +1021,7 @@ static lfmproxy* get_proxy()
 
 void communication_init()
 {
-	process_proxy = proxy_init();
+	process_proxy = proxy_init();	
 }
 
 void communication_destroy()
@@ -864,35 +1029,29 @@ void communication_destroy()
 	proxy_destroy(process_proxy);
 }
 
-void call_method(const lfmget* call, const lfmparametervalue** parameter, void* callback, void* user_data)
+void call_method(const lfmget* call, lfmparametervalue*** parameters, void* callback, void* user_data)
 {
+	lfmparametervalue* parameter = g_new0(lfmparametervalue, 2);
+	parameter-&gt;name = METHOD_KEY;
+	parameter-&gt;value = call-&gt;method-&gt;name;	
+	addv(lfmparametervalue, *parameters, parameter);
+	
+	parameter++;
+	
+	parameter-&gt;name = API_PARAMETER;
+	parameter-&gt;value = API_KEY;
+	addv(lfmparametervalue, *parameters, parameter);
+	
 	if(call-&gt;method-&gt;type == GET_METHOD)
-		proxy_request(get_proxy(), call, parameter, callback, user_data);
+		proxy_request(get_proxy(), call, parameters, callback, user_data);
 	else
-		proxy_post(get_proxy(), call, parameter, callback, user_data);
-}
-
-void fill_parameters(lfmparametervalue** values, const lfmmethod* method, va_list* vl)
-{	
-	lfmparameter const * iterator = method-&gt;parameters;
+		proxy_post(get_proxy(), call, parameters, callback, user_data);
 	
-	gpointer data = NULL;
-	
-	while((data = va_arg(*vl, void*)))
-	{
-		 if(!(iterator-&gt;name))
-		 	break;
-
-		 g_warn_if_fail(iterator-&gt;converter);
-		 gchar* output = iterator-&gt;converter(data);
-		 		 
-		 lfmparametervalue* value = g_new(lfmparametervalue, 1);
-		 value-&gt;name = iterator-&gt;name;
-		 value-&gt;value = output;
-		 addv(lfmparametervalue, values, value);
-		 	
-		 iterator++;
-	}
+	//cleanup all in this function added parameters	
+	size_t count = countv((void**)*parameters);
+	(*parameters)[count - 1] = NULL;
+	(*parameters)[count - 2] = NULL;
+	g_free(--parameter);
 }
 
 gchar* utf8_array2csl(gpointer data)
@@ -942,10 +1101,63 @@ G_GNUC_NULL_TERMINATED void call_method_with_parameters(const lfmget* call, gpoi
 	va_list vl;
 	va_start(vl, user_data);
 	
-	fill_parameters(parameters, call-&gt;method, &amp;vl);
+	lfmparameter const * iterator = call-&gt;method-&gt;parameters;
+	
+	gpointer data = NULL;
+	guint parameter_index = 0;
+	gboolean optional = FALSE;
+	
+	//collect all converted strings so we
+	//can cleanup later on
+	createv(gchar, converted_strings);
+	
+	while((data = va_arg(vl, void*)))
+	{
+		if(!(iterator-&gt;name))
+		{
+			if(optional)
+			{
+				communication_printerr(&quot;More parameters supplied than can be mapped&quot;);
+				break;
+			}
+			else
+			{
+				iterator = call-&gt;method-&gt;optional_parameters;
+				optional = TRUE;
+				
+				if(!(iterator-&gt;name))
+					break; //we have no optional parameters
+			}
+		}
+		
+		gchar* output = NULL;
+		
+		if(iterator-&gt;converter)
+		{
+			output = iterator-&gt;converter(data);
+			//save converted string for cleanup		
+			addv(gchar, converted_strings, output);
+		}
+		else
+			output = data;
+		 		 
+		lfmparametervalue* value = g_new(lfmparametervalue, 1);
+		value-&gt;name = iterator-&gt;name;
+		value-&gt;value = output;
+		addv(lfmparametervalue, parameters, value);
+	
+		parameter_index++;	 	
+		iterator++;
+	}
 	
-	call_method(call, (const lfmparametervalue**)parameters, callback, user_data);
+	//check whether we have all parameters mapped
+	if(!optional &amp;&amp; (iterator-&gt;name) &amp;&amp; ((iterator + 1)-&gt;name))
+		communication_printerr(&quot;There still are parameters not mapped&quot;);
+	
+	call_method(call, &amp;parameters, callback, user_data);
 	
 	va_end(vl);
-	destroyv(lfmparametervalue, parameters);
+	
+	destroyv(gchar, converted_strings);
+	destroyv(lfmparametervalue, parameters);	
 }</diff>
      <filename>communication.c</filename>
    </modified>
    <modified>
      <diff>@@ -43,7 +43,6 @@ struct lfmparameter
 {
 	const gchar* name;
 	type_converter converter;
-	gboolean is_optional;
 };
 
 typedef struct lfmparameter lfmparameter;
@@ -58,10 +57,13 @@ struct lfmmethod
 {
 	const gchar* name;
 	const enum method_type type;
-	const lfmparameter parameters[2];
+	const lfmparameter parameters[5];
+	const lfmparameter optional_parameters[5];
 	const lfmerror specific_errors[5];	
 };
 
+typedef struct lfmmethod lfmmethod;
+
 enum data_type
 {
 	DATA_UTF8,
@@ -72,7 +74,30 @@ enum data_type
 	DATA_VOID
 };
 
-typedef struct lfmmethod lfmmethod;
+struct utf8_syncer
+{
+	gchar* string;
+	GError* error;
+	GCond* signal;
+};
+
+void utf8_sync(const gchar* string, gpointer user_data, GError* error);
+
+#define IMPLEMENT_SYNC_UTF8(function, ...) \
+	struct utf8_syncer _syncer;\
+	_syncer.string = NULL;\
+	_syncer.error = NULL;\
+	_syncer.signal = g_cond_new();\
+	function(__VA_ARGS__, utf8_sync, &amp;_syncer);\
+	GMutex* _mutex = g_mutex_new();\
+	g_cond_wait(_syncer.signal, _mutex);\
+	g_mutex_free(_mutex);\
+	if(_syncer.error)\
+	{\
+		*error = _syncer.error;\
+		return NULL;\
+	}\
+	return _syncer.string
 	
 struct lfmget
 {
@@ -83,21 +108,10 @@ struct lfmget
 
 typedef struct lfmget lfmget;
 
-struct lfmparametervalue
-{
-	const gchar* name;
-	const gchar* value;
-};
-
-typedef struct lfmparametervalue lfmparametervalue;
-
 gchar* utf8_array2csl(gpointer array);
 gchar* uint2utf8(gpointer array);
 
-
-void fill_parameters(lfmparametervalue** values, const lfmmethod* method, va_list* vl);
-
-void call_method(const lfmget* call, const lfmparametervalue** parameter, void* callback, void* user_data);
+//variable argument have to be ordered as defined in call
 G_GNUC_NULL_TERMINATED void call_method_with_parameters(const lfmget* call, gpointer callback, gpointer user_data, ...);
 
 #endif /*COMMUNICATION_H_*/</diff>
      <filename>communication.h</filename>
    </modified>
    <modified>
      <diff>@@ -10,21 +10,21 @@ type** pointer = g_new(type*, 1);\
 
 #define destroyv(type, pointer) \
 {\
-	type** iterator = pointer;\
-	while(*iterator)\
+	type** _iterator = pointer;\
+	while(*_iterator)\
 	{\
-		g_free(*iterator);\
-		iterator++;\
+		g_free(*_iterator);\
+		_iterator++;\
 	}\
 	g_free(pointer);\
 }
 
 #define addv(type, elements, element) \
 {\
-	guint length = countv((void**)elements);\
-	elements = g_renew(type*, elements, length += 2);\
-	elements[length - 2] = element;\
-	elements[length - 1] = NULL;\
+	guint _length = countv((void**)(elements));\
+	(elements) = g_renew(type*, (elements), _length + 2);\
+	(elements)[_length] = element;\
+	(elements)[_length + 1] = NULL;\
 }
 
 void xwax_vprinterr(const char* module_name, const char* format, va_list args);</diff>
      <filename>include.h</filename>
    </modified>
    <modified>
      <diff>@@ -139,8 +139,8 @@ int main(int argc, const char* args[])
 	
 	increaseCall();
 	createv(gchar, tags);
-	addv(gchar, tags, &quot;test1&quot;);
-	addv(gchar, tags, &quot;test2&quot;);
+	addv(gchar, tags, g_strdup(&quot;test1&quot;));
+	addv(gchar, tags, g_strdup(&quot;test2&quot;));
 	artist_add_tags(atst, (const gchar**)tags, void_func, &quot;artist_add_tags&quot;);
 	destroyv(gchar, tags);
 	</diff>
      <filename>lastfm_test.c</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>355c354d7d76a42611b4d93ba56dad70a23a9d36</id>
    </parent>
  </parents>
  <author>
    <name>LCID Fire</name>
    <email>lcid-fire@gmx.net</email>
  </author>
  <url>http://github.com/LCID-Fire/liblastfm/commit/953b92fd83b8894e5e5889d44766a7a5882f4c19</url>
  <id>953b92fd83b8894e5e5889d44766a7a5882f4c19</id>
  <committed-date>2008-07-18T06:06:28-07:00</committed-date>
  <authored-date>2008-07-18T06:06:28-07:00</authored-date>
  <message>Declare method in every detail
Introduced first synchronous functions
Implemented post (not tested yet)
Simplified communication interface</message>
  <tree>a84940e48bd0378e16881cabafe29e83ee4772d2</tree>
  <committer>
    <name>LCID Fire</name>
    <email>lcid-fire@gmx.net</email>
  </committer>
</commit>
