<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -59,7 +59,7 @@ 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_TAGS},
 	{&amp;album_method_declarations[add_tags], {}, DATA_VOID},
 	{&amp;album_method_declarations[remove_tag], {}, DATA_VOID},
 };</diff>
      <filename>album.c</filename>
    </modified>
    <modified>
      <diff>@@ -82,14 +82,14 @@ enum primary_info
 
 lfmget related_methods[] =
 {
-	{&amp;artist_method_declarations[get_events],          {&quot;events&quot;, &quot;event&quot;, &quot;id&quot;}, DATA_UINT},
-	{&amp;artist_method_declarations[get_similar_artists], {&quot;similarartists&quot;, &quot;artist&quot;, &quot;name&quot;}, DATA_UTF8},
-	{&amp;artist_method_declarations[get_info],            {&quot;artist&quot;, &quot;similar&quot;, &quot;artist&quot;, &quot;name&quot;}, DATA_UTF8},
-	{&amp;artist_method_declarations[get_info],            {&quot;artist&quot;, &quot;tags&quot;, &quot;tag&quot;, &quot;name&quot;}, DATA_UTF8},
-	{&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_events],          {&quot;events&quot;, &quot;event&quot;, &quot;id&quot;}, DATA_EVENTS},
+	{&amp;artist_method_declarations[get_similar_artists], {&quot;similarartists&quot;, &quot;artist&quot;, &quot;name&quot;}, DATA_ARTISTS},
+	{&amp;artist_method_declarations[get_info],            {&quot;artist&quot;, &quot;similar&quot;, &quot;artist&quot;, &quot;name&quot;}, DATA_ARTISTS},
+	{&amp;artist_method_declarations[get_info],            {&quot;artist&quot;, &quot;tags&quot;, &quot;tag&quot;, &quot;name&quot;}, DATA_TAGS},
+	{&amp;artist_method_declarations[get_top_albums],      {&quot;topalbums&quot;, &quot;album&quot;}, DATA_ALBUMS},
+	{&amp;artist_method_declarations[get_top_fans],        {&quot;topfans&quot;, &quot;user&quot;, &quot;name&quot;}, DATA_USERS},
+	{&amp;artist_method_declarations[get_top_tags],        {&quot;toptags&quot;, &quot;tag&quot;, &quot;name&quot;}, DATA_TAGS},
+	{&amp;artist_method_declarations[get_top_tracks],      {&quot;toptracks&quot;, &quot;track&quot;, &quot;name&quot;}, DATA_TRACKS},
 	{&amp;artist_method_declarations[add_tags],            {}, DATA_VOID},
 	{&amp;artist_method_declarations[remove_tag],          {}, DATA_VOID}
 };</diff>
      <filename>artist.c</filename>
    </modified>
    <modified>
      <diff>@@ -8,7 +8,6 @@
 
 enum error_codes
 {
-	CALLBACK_EOF          = -1,
 	INVALID_SERVICE       = 2,
     INVALID_METHOD        = 3,
     AUTHENTICATION_FAILED = 4,
@@ -21,6 +20,7 @@ enum error_codes
     SUBSCRIBERS_ONLY      = 12
 };
 
+//one element callbacks - called only once
 typedef void (*void_callback)(gpointer user_data, GError* error);
 typedef void (*utf8_callback)(const gchar* utf8, gpointer user_data, GError* error);
 typedef void (*url_callback)(const gchar* url, gpointer user_data, GError* error);
@@ -28,11 +28,14 @@ typedef void (*uint_callback)(guint digit, gpointer user_data, GError* error);
 typedef void (*boolean_callback)(gboolean istrue, gpointer user_data, GError* error);
 typedef void (*date_time_callback)(struct tm, gpointer user_data, GError* error);
 
-typedef void (*artists_callback)(const gchar* artist_name, gpointer user_data, GError* error);
-typedef void (*tags_callback)(const gchar* tag_name,  gpointer user_data, GError* error);
-typedef void (*tracks_callback)(const gchar* artist_name, const gchar* track_name, gpointer user_data, GError* error);
-typedef void (*albums_callback)(const gchar* artist_name, const gchar* album_name, gpointer user_data, GError* error);
-typedef void (*events_callback)(guint event_id,  gpointer user_data, GError* error);
-typedef void (*users_callback)(const gchar* user_name,  gpointer user_data, GError* error);
+//mutliple element callbacks
+//terminated by call with is_end == TRUE
+typedef void (*multi_utf8_callback)(const gchar* artist_name, gpointer user_data, GError* error, gboolean is_end);
+typedef multi_utf8_callback artists_callback;
+typedef multi_utf8_callback tags_callback;
+typedef multi_utf8_callback tracks_callback;
+typedef multi_utf8_callback albums_callback;
+typedef multi_utf8_callback events_callback;
+typedef multi_utf8_callback users_callback;
 
 #endif /*CALLBACK_H_*/</diff>
      <filename>callback.h</filename>
    </modified>
    <modified>
      <diff>@@ -31,11 +31,8 @@ void utf8_sync(const gchar* string, gpointer user_data, GError* error)
 	syncer-&gt;string = g_strdup(string);
 	syncer-&gt;error = error;
 	
-	if(error &amp;&amp; error-&gt;code == CALLBACK_EOF)
-	{
-		//we are ready to get back to the synced version
-		g_cond_signal(syncer-&gt;signal);
-	}
+	//we are ready to get back to the synced version
+	g_cond_signal(syncer-&gt;signal);
 }
 
 size_t sum_uintv(guint* array)
@@ -403,6 +400,20 @@ enum data_type get_type(const struct xml_parser* parser)
 		return parser-&gt;call-&gt;data_parser;
 }
 
+#define addsizev(array, value) \
+{\
+	size_t* _iterator = array;\
+	size_t _count = 0;\
+	while(*_iterator != 0)\
+	{\
+		_count++;\
+		_iterator++;\
+	}\
+	array = g_renew(size_t, array, _count += 2);\
+	array[_count - 2] = value;\
+	array[_count - 1] = 0;\
+}
+
 static const char root_element_name[] = &quot;lfm&quot;;
 
 gboolean is_correct_structure(const gchar* current_element, GMarkupParseContext* context, const gchar** path)
@@ -450,7 +461,50 @@ void xml_parse_start
 {	
 	struct xml_parser* parser = user_data;
 	
-	if(strcmp(element_name, root_element_name) == 0)
+	if(!parser-&gt;is_error &amp;&amp; parser-&gt;collect)
+	{
+		//since we are to collect the underlying xml
+		//we also have to collect the underlying tags
+		
+		//collect &lt;
+		addv(gchar, parser-&gt;texts, g_strdup(&quot;&lt;&quot;));
+		addsizev(parser-&gt;text_lengths, 1);
+		
+		//collect element name
+		addv(gchar, parser-&gt;texts, g_strdup(element_name));
+		addsizev(parser-&gt;text_lengths, strlen(element_name));
+		
+		//collect attributes
+		const gchar** name_iterator = attribute_names;
+		const gchar** value_iterator = attribute_values;
+		
+		while(*name_iterator)
+		{
+			//collect attribute name
+			addv(gchar, parser-&gt;texts, g_strdup(*name_iterator));
+			addsizev(parser-&gt;text_lengths, strlen(*name_iterator));
+			
+			//collect =&quot;
+			addv(gchar, parser-&gt;texts, g_strdup(&quot;=\&quot;&quot;));
+			addsizev(parser-&gt;text_lengths, 2);
+			
+			//collect attribute value
+			addv(gchar, parser-&gt;texts, g_strdup(*value_iterator));
+			addsizev(parser-&gt;text_lengths, strlen(*value_iterator));
+			
+			//collect &quot;
+			addv(gchar, parser-&gt;texts, g_strdup(&quot;\&quot;&quot;));
+			addsizev(parser-&gt;text_lengths, 1);
+		
+			name_iterator++;
+			value_iterator++;
+		}
+		
+		//collect &gt;
+		addv(gchar, parser-&gt;texts, g_strdup(&quot;&gt;&quot;));
+		addsizev(parser-&gt;text_lengths, 1);
+	}
+	else if(strcmp(element_name, root_element_name) == 0)
 	{
 		const gchar** name_iterator = attribute_names;
 		const gchar** value_iterator = attribute_values;
@@ -532,7 +586,7 @@ void invoke_callback(enum data_type type, const gchar* text, gpointer callback,
 			((void_callback)callback)(user_data, error);
 			break;
 		}
-		default: //DATA_UTF8 OR DATA_URL
+		default: //DATA_UTF8, DATA_URL, DATA_MULTI_UTF8
 		{
 			((utf8_callback)callback)(text, user_data, error);
 			break;
@@ -540,6 +594,22 @@ void invoke_callback(enum data_type type, const gchar* text, gpointer callback,
 	}
 }
 
+gboolean end_multi_interface(enum data_type type, gpointer callback, gpointer user_data)
+{
+	switch(type)
+	{
+		case DATA_MULTI_UTF8:
+		{
+			((multi_utf8_callback)callback)(NULL, user_data, NULL, TRUE);
+			return TRUE;
+		}
+		default:
+		{
+			return FALSE;
+		}				
+	}
+}
+
 // Called for close tags &lt;/foo&gt;
 void xml_parse_end
 (
@@ -551,14 +621,27 @@ void xml_parse_end
 {	
 	struct xml_parser* parser = user_data;
 	
-	if((strcmp(element_name, root_element_name) == 0))
-	{
-		GError* le = g_error_new(1, CALLBACK_EOF, &quot;EOF&quot;);
-		invoke_callback(parser-&gt;call-&gt;data_parser, NULL, parser-&gt;callback, parser-&gt;user_data, le);
-	} 
+	if
+	(
+		(strcmp(element_name, root_element_name) == 0)
+	 	&amp;&amp; end_multi_interface(parser-&gt;call-&gt;data_parser, parser-&gt;callback, parser-&gt;user_data)
+	)
+		return;
 
 	if(!is_correct_structure(element_name, context, get_paths(parser)))
+	{
+		//did we collect something before?
+		if(parser-&gt;collect)
+		{
+			if(!parser-&gt;is_error)
+			{
+				addv(gchar, parser-&gt;texts, g_strdup(element_name));
+				addsizev(parser-&gt;text_lengths, strlen(element_name));
+			}
+		}
+	
 		return;
+	}
 	
 	parser-&gt;collect = FALSE;
 	
@@ -639,20 +722,8 @@ void xml_parse_text
 	if(!parser-&gt;collect)
 		return; //not in desired structure
 	
-	addv(gchar, parser-&gt;texts,  g_memdup(text, text_len));
-	
-	size_t* iterator = parser-&gt;text_lengths;
-	
-	size_t count = 0;
-	while(*iterator != 0)
-	{
-		count++;
-		iterator++;
-	}
-	
-	parser-&gt;text_lengths = g_renew(size_t, parser-&gt;text_lengths, count += 2);		
-	parser-&gt;text_lengths[count - 2] = text_len;
-	parser-&gt;text_lengths[count - 1] = 0;		
+	addv(gchar, parser-&gt;texts, g_memdup(text, text_len));
+	addsizev(parser-&gt;text_lengths, text_len);		
 }
 
 // Called for strings that should be re-saved verbatim in this same
@@ -776,7 +847,7 @@ void proxy_end_process(lfmproxy* proxy)
 
 lfmproxy* proxy_init()
 {	
-	http_proxy_init();
+	//http_proxy_init();
 	lfmproxy* proxy = g_new(lfmproxy, 1);
 	proxy-&gt;multi_handle = curl_multi_init();
 	
@@ -809,7 +880,7 @@ lfmproxy* proxy_init()
 
 void proxy_destroy(lfmproxy* proxy)
 {
-	http_proxy_destroy();
+	//http_proxy_destroy();
 	
 	if(!proxy)
 		return;</diff>
      <filename>communication.c</filename>
    </modified>
    <modified>
      <diff>@@ -71,7 +71,14 @@ enum data_type
 	DATA_DATE_TIME,
 	DATA_BOOLEAN,
 	DATA_UINT,
-	DATA_VOID
+	DATA_VOID,
+	DATA_MULTI_UTF8,
+	DATA_TAGS = DATA_MULTI_UTF8,
+	DATA_ALBUMS = DATA_MULTI_UTF8,
+	DATA_ARTISTS = DATA_MULTI_UTF8,
+	DATA_EVENTS = DATA_MULTI_UTF8,
+	DATA_TRACKS = DATA_MULTI_UTF8,
+	DATA_USERS = DATA_MULTI_UTF8
 };
 
 struct utf8_syncer</diff>
      <filename>communication.h</filename>
    </modified>
    <modified>
      <diff>@@ -21,68 +21,40 @@ void void_func(gpointer user_data, GError* error)
 {
 	const char* func_name = user_data;
 	if(error)
-	{
-		if(error-&gt;code == CALLBACK_EOF)
-		{
-			//g_print(&quot;%s: [DONE]\n&quot;, func_name);
-			decreaseCall();
-		}
-		else
-			g_printerr(&quot;%s: [ERROR] %s\n&quot;, func_name, error-&gt;message);
-	}
+		g_printerr(&quot;%s: [ERROR] %s\n&quot;, func_name, error-&gt;message);
 	else
 		g_print(&quot;%s: [OK]\n&quot;, func_name);
+	
+	decreaseCall();
 }
 
 void utf8_func(const gchar* string, gpointer user_data, GError* error)
 {
 	const char* func_name = user_data;
 	if(error)
-	{
-		if(error-&gt;code == CALLBACK_EOF)
-		{
-			//g_print(&quot;%s: [DONE]\n&quot;, func_name);
-			decreaseCall();
-		}
-		else
-			g_printerr(&quot;%s: [ERROR] %s\n&quot;, func_name, error-&gt;message);
-	}
+		g_printerr(&quot;%s: [ERROR] %s\n&quot;, func_name, error-&gt;message);
 	else
 		g_print(&quot;%s: [OK] %s\n&quot;, func_name, string);
+	
+	decreaseCall();
 }
 
 void uint_func(guint count, gpointer user_data, GError* error)
 {
 	const char* func_name = user_data;
 	if(error)
-	{
-		if(error-&gt;code == CALLBACK_EOF)
-		{
-			//g_print(&quot;%s: [DONE]\n&quot;, func_name);
-			decreaseCall();
-		}
-		else
-			g_printerr(&quot;%s: [ERROR] %s\n&quot;, func_name, error-&gt;message);
-	}
+		g_printerr(&quot;%s: [ERROR] %s\n&quot;, func_name, error-&gt;message);
 	else
 		g_print(&quot;%s: [OK] %u\n&quot;, func_name, count);
 	
-	
+	decreaseCall();
 }
 
 void boolean_func(gboolean success, gpointer user_data, GError* error)
 {
 	const char* func_name = user_data;
 	if(error)
-	{
-		if(error-&gt;code == CALLBACK_EOF)
-		{
-			//g_print(&quot;%s: [DONE]\n&quot;, func_name);
-			decreaseCall();
-		}
-		else
-			g_printerr(&quot;%s: [ERROR] %s\n&quot;, func_name, error-&gt;message);
-	}
+		g_printerr(&quot;%s: [ERROR] %s\n&quot;, func_name, error-&gt;message);
 	else
 		g_print(&quot;%s: [OK] %s\n&quot;, func_name, success ? &quot;TRUE&quot; : &quot;FALSE&quot;);
 	
@@ -93,21 +65,33 @@ void dt_func(struct tm dt, gpointer user_data, GError* error)
 {
 	const char* func_name = user_data;
 	if(error)
+		g_printerr(&quot;%s: [ERROR] %s\n&quot;, func_name, error-&gt;message);
+	else
 	{
-		if(error-&gt;code == CALLBACK_EOF)
-		{
-			//g_print(&quot;%s: [DONE]\n&quot;, func_name);
-			decreaseCall();
-		}
-		else
-			g_printerr(&quot;%s: [ERROR] %s\n&quot;, func_name, error-&gt;message);
+		char time_buffer[256];
+		strftime(time_buffer, 255, &quot;%a, %d %b %Y %H:%M:%S %z&quot;, &amp;dt);
+	
+		g_print(&quot;%s: [OK] %s\n&quot;, func_name, time_buffer);
 	}
-	else
-		g_print(&quot;%s: [OK] Month: %u\n&quot;, func_name, dt.tm_mon);
 		
 	decreaseCall();
 }
 
+void multi_utf8_func(const gchar* string, gpointer user_data, GError* error, gboolean is_end)
+{
+	if(is_end)
+	{
+		decreaseCall();
+		return;
+	}
+		
+	const char* func_name = user_data;
+	if(error)
+		g_printerr(&quot;%s: [ERROR] %s\n&quot;, func_name, error-&gt;message);
+	else
+		g_print(&quot;%s: [OK] %s\n&quot;, func_name, string);
+}
+
 int main(int argc, const char* args[])
 {	
 	lastfm_init();
@@ -166,7 +150,7 @@ int main(int argc, const char* args[])
 	increaseCall();
 	album_get_play_count(atst, albm, uint_func, &quot;album_get_play_count&quot;);
 	increaseCall();
-	album_get_top_tags(atst, albm, utf8_func, &quot;album_get_top_tags&quot;);
+	album_get_top_tags(atst, albm, multi_utf8_func, &quot;album_get_top_tags&quot;);
 		
 	GMutex* mutex = g_mutex_new();   
 	g_cond_wait(cond, mutex);</diff>
      <filename>lastfm_test.c</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>6b178a6e2f649961be99137aaeea964e41e04a7d</id>
    </parent>
  </parents>
  <author>
    <name>LCID Fire</name>
    <email>lcid-fire@gmx.net</email>
  </author>
  <url>http://github.com/LCID-Fire/liblastfm/commit/2c9dc967f250160e1ae900efc1493a1cd2546451</url>
  <id>2c9dc967f250160e1ae900efc1493a1cd2546451</id>
  <committed-date>2008-07-19T06:49:56-07:00</committed-date>
  <authored-date>2008-07-19T06:49:56-07:00</authored-date>
  <message>Simplified callbacks:
Single element are no longer terminated by EOF
Multi element are ended by explicit is_end flag</message>
  <tree>75c66a8bbf3bcdc021c9f80746c9ed2ca340d2d6</tree>
  <committer>
    <name>LCID Fire</name>
    <email>lcid-fire@gmx.net</email>
  </committer>
</commit>
