Index: blogclient.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/blogclient/blogclient.install,v retrieving revision 1.1 diff -u -d -b -w -r1.1 blogclient.install --- blogclient.install 13 Jul 2006 00:55:16 -0000 1.1 +++ blogclient.install 9 Aug 2006 04:09:43 -0000 @@ -50,3 +50,8 @@ function blogclient_update_1() { return _system_update_utf8(array('blogs')); } \ No newline at end of file + +function blogclient_update_2() { + $ret[] = update_sql("ALTER TABLE {blogs} ADD COLUMN defaultpost tinyint(1) NOT NULL default 1"); + return $ret; +} Index: blogclient.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/blogclient/blogclient.module,v retrieving revision 1.2 diff -u -d -b -w -r1.2 blogclient.module --- blogclient.module 13 Jul 2006 00:55:16 -0000 1.2 +++ blogclient.module 9 Aug 2006 04:09:43 -0000 @@ -5,36 +5,53 @@ function blogclient_help($section) { switch ($section) { case 'admin/modules#description': + case 'admin/settings/modules#description': // appears on the admin module selection page return t('Allows users to post to blogs at the same time as thier drupal posts.'); } } function blogclient_menu($may_cache) { + global $user; $items = array(); if ($may_cache) { $items[] = array( - 'path' => 'blogclient', + 'path' => 'syndicate/blog', 'title' => t('blog client'), 'access' => user_access('access blogclient'), 'callback' => 'blogclient_list', ); } else { - if (arg(0) == 'blogclient') { + if (arg(0) == 'syndicate' && arg(1) == 'blog') { $items[] = array( - 'path' => 'blogclient/edit', - 'title' => arg(2) ? t('edit') : t('add'), + 'path' => 'syndicate/blog/add', + 'title' => t('add'), + 'callback' => 'blogclient_edit', + 'access' => user_access('admin blogclient') || (user_access('access blogclient') && (db_result(db_query('SELECT COUNT(blogid) FROM {blogs} WHERE uid = %d', $user->uid)) < 5)), + 'type' => MENU_LOCAL_TASK, + ); + if (arg(2) == 'edit' && is_numeric(arg(3))) { + $items[] = array( + 'path' => 'syndicate/blog/edit', + 'title' => t('edit'), 'callback' => 'blogclient_edit', 'access' => user_access('access blogclient'), 'type' => MENU_LOCAL_TASK, ); + } $items[] = array( - 'path' => 'blogclient/list', + 'path' => 'syndicate/blog/list', 'type' => MENU_DEFAULT_LOCAL_TASK, - 'title' => t('list'), + 'title' => t('my blogs'), 'weight' => -10, ); + $items[] = array( + 'path' => 'syndicate/blog/delete', + 'type' => MENU_CALLBACK, + 'title' => t('Delete'), + 'callback' => 'blogclient_delete', + ); } } return $items; @@ -44,37 +61,131 @@ return array('access blogclient', 'admin blogclient'); } + function blogclient_list($uid = 0) { global $user; if (!$uid) { $uid = $user->uid; } - $r = db_query('SELECT * FROM {blogs} WHERE uid = %d', $uid); + $r = db_query('SELECT title, blogid AS blogid FROM {blogs} WHERE uid = %d ORDER BY title', $uid); + if (!db_num_rows($r)) { + drupal_goto('syndicate/blog/add'); + } $list = array(); while ($blog = db_fetch_object($r)) { - $rows[] = array($blog->title, $blog->remote_id, l('edit', "blogclient/edit/$blog->blogid")); + $rows[] = array( + check_plain($blog->title), + l('edit', "syndicate/blog/edit/$blog->blogid"), + l('delete', "syndicate/blog/delete/$blog->blogid"), + ); } - return theme('table', array(), $rows, array('width' => '100%')); + $output = theme('table', array(), $rows, array('width' => '100%')); + if (!user_access('admin blogclient') && db_result(db_query('SELECT COUNT(blogid) FROM {blogs} WHERE uid = %d', $user->uid)) >= 5) { + $output .= t('

Note that you have reached the maximum number of blogs allowed.

'); + } + return $output; } -function blogclient_edit($blogid = 0, $form_values = array()) { +function blogclient_delete($blogid, $from_edit = 0) { + if (!$title = db_result(db_query('SELECT title FROM {blogs} WHERE blogid = %d', $blogid))) { + drupal_goto('syndicate/blog'); + } + if (!isset($_POST['op']) || $_POST['op'] != t('Confirm')) { + $edit = $_POST['edit']; - $blogid = arg(2); + $form['nodes'] = array('#prefix' => '', '#tree' => TRUE); + $form['nodes'][$nid] = array('#type' => 'hidden', '#value' => $nid, '#prefix' => '
  • ', '#suffix' => check_plain($title) ."
  • \n"); + $form['operation'] = array('#type' => 'hidden', '#value' => 'delete'); + + return confirm_form('blogclient_delete', $form, + t('

    Do you really want to delete %title? This action cannot be undone.

    ', array('%title' => check_plain($title))), + 'syndicate/blog', t('This action cannot be undone.'), + t('Confirm'), t('Cancel')); + } + else { + drupal_set_message(t('%title deleted.', array('%title' => check_plain($title)))); + db_query('DELETE FROM {blogs} WHERE blogid = %d', $blogid); + drupal_goto('syndicate/blog'); + } +} + +function blogclient_type_map ($type = NULL) { + $map = array( + 'Blogger.com' => 'atom', + 'Livejournal.com' => 'atom', + 'Typepad.com' => 'atom', + 'Wordpress.com' => 'metaweblog', + 'Spaces.MSN.com' => 'metaweblog', + 'atom' => 'atom', + 'metaweblog' => 'metaweblog', + 'blogger' => 'blogger', + ); + if (!isset($type)) { + return $map; + } + if (isset($map[$type])) { + return $map[$type]; + } +} + +function blogclient_edit($blogid=0) { if ($blogid) { - $form_values = db_fetch_array(db_query('SELECT * FROM {blogs} WHERE blogid = %d', $blogid)); + $edit = db_fetch_array(db_query('SELECT * FROM {blogs} WHERE blogid = %d', $blogid)); if (!user_access('admin blogclient') && $edit['uid'] != $user->uid) { - drupal_goto('blogclient'); + drupal_goto('syndicate/blog/add'); + } + $r = db_query("SELECT blogid, defaultpost, title, endpoint, remote_id, type FROM {blogs} WHERE url = '%s'", $edit['url']); + while ($endpoint = db_fetch_array($r)) { + $endpoints[$endpoint['blogid']] = $endpoint; + } + } + else { + unset($endpoints); + } + $next = t('Next'); + $save = t('Save'); + $manual = t('Configure manually'); + $delete = t('Delete'); + + if ($_POST['op']) { + $edit = $_POST['edit']; + switch($_POST['op']) { + case $next: + { + $edit['url'] = strtolower($edit['url']); + if (!valid_url($edit['url'])) { + form_set_error('url',t('The URL seems invalid.')); + break; + } + $discover = blogclient_discover($edit['url'], $edit['name'], $edit['pass']); + if ($discover == -401) { + drupal_set_message(t('Unable to log in with this username and password')); + if (strpos($edit['url'], 'spaces.msn.com') !== FALSE) { + drupal_set_message(t('For MSN Spaces, you need to enable Email publishing and use the name of your Space for username and the secret word from Email publishing as password.')); + } + } + elseif ($endpoints = $discover) { + if (count($endpoints) > 1) { + drupal_set_message(t('Your blogs have been found and we are ready to post to it.')); + } + else { + drupal_set_message(t('Your blog has been found and we are ready to post to it.')); + } + } + else { + drupal_set_message(t('We were unable to configure the system to be able to post to your blog. Try configuring manually.')); + } + break; + } + case $manual: + $endpoints = ''; // set endpoints to something empty + break; + case $delete: + drupal_goto("syndicate/blog/delete/$blogid/1"); + break; } } $form_values = array_merge($form_values,$_POST['edit']); - $form['title'] = array( - '#type' => 'textfield', - '#title' => t('Name'), - '#default_value' => $form_values['title'], - '#size' => 40, - '#maxlength' => 255, - '#description' => t('Name of this blog'), - ); $form['url'] = array( '#type' => 'textfield', '#title' => t('URL'), @@ -89,86 +200,157 @@ '#default_value' => $form_values['name'], '#size' => 15, '#maxlength' => 64, - );$form['pass'] = array( + ); + $form['pass'] = array( '#type' => 'password', '#title' => t('Password'), '#default_value' => $form_values['pass'], '#size' => 15, '#maxlength' => 64, ); - $form['endpoint'] = array( + + if (!isset($endpoints) && !$form_values['stage2']) { + $form['next'] = array( + '#type' => 'button', + '#value' => $next, + ); + $form['save'] = array( + '#type' => 'submit', + '#value' => $manual, + ); + } + else { + $rows = array(); + $options = drupal_map_assoc(array_keys(blogclient_type_map())); + $form['stage2'] = array('#type' => 'hidden','#value' => '1'); + if (empty($endpoints)) { + $endpoints = array(array()); + } + $value = implode('|', array_keys($endpoints)); + $form['endpoints'] = array('#type'=>'hidden', '#value'=>$value); + + foreach ($endpoints as $current_blogid => $endpoint) { + $form['defaultpost']['defaultpost'. $current_blogid] = array( + '#type' => 'checkbox', + '#title' => '', + '#return_value' => 1, + '#default_value' => $blogid ? $endpoint['defaultpost'] : 1, + ); + $form['title']['title'. $current_blogid] = array( '#type' => 'textfield', - '#title' => t('Endpoint'), - '#default_value' => $form_values['endpoint'], - '#size' => 40, + '#title' => '', + '#default_value' => $endpoint['title'], + '#size' => 30, '#maxlength' => 255, - '#description' => t('The endpoint we should post to, for example https://www.blogger.com/atom/1234567890. Try pressing autodiscover below if you do not know the value of this.'), ); - $form['remote_id'] = array( + $form['endpoint']['endpoint'. $current_blogid] = array( '#type' => 'textfield', - '#title' => t('Remote id'), - '#default_value' => $form_values['remote_id'], - '#size' => 15, - '#maxlength' => 64, + '#title' => '', + '#default_value' => $endpoint['endpoint'], + '#size' => 20, + '#maxlength' => 255, ); - $form['type'] = array( + if ($endpoint['type'] == 'atom') { + $form['remote_id']['remote_id'. $current_blogid] = array( + '#type' => 'hidden', + '#value' => '', + ); + } + else { + $form['remote_id']['remote_id'. $current_blogid] = array( + '#type' => 'textfield', + '#size' => 10, + '#maxsize' => 30, + '#default_value' => $endpoint['remote_id'], + ); + } + $form['type']['type'. $current_blogid] = array( '#type' => 'select', - '#title' => t('Type'), - '#default_value' => $form_values['type'], - '#options' => drupal_map_assoc(array('atom', 'metaweblog', 'blogger')), + '#title' => '', + '#default_value' => $endpoint['type'], + '#options' => $options, ); - $form['save'] = array( - '#type' => 'submit', - '#value' => t('Save'), + $form['save']['save'. $current_blogid] = array( + '#type' => 'checkbox', + '#title' => '', + '#return_value' => 1, + '#default_value' => 1, ); - $form['autodiscover'] = array( - '#type' => 'button', - '#value' => t('Autodiscover'), + } + + $form['next'] = array( + '#type' => 'submit', + '#value' => $save, ); + if ($blogid) { - $form['blogid'] = array( - '#type' => 'hidden', - '#value' => $blogid, + $form['delete'] = array( + '#type' => 'submit', + '#value' => $delete, ); } - if ($_POST['op'] == t('Autodiscover')) { - $endpoint = blogclient_discover($form_values['url'], $form_values['name'], $form_values['pass']); - $form['endpoint']['#value'] = $endpoint['endpoint']; - $form['type']['#value'] = $endpoint['type']; - $form['remote_id']['#value'] = $endpoint['remote_id']; + return drupal_get_form('blogclient_autodiscover', $form); + } - if (!$form_values['title']) { - $form['title']['#value'] = $endpoint['title']; + return drupal_get_form('blogclient_edit', $form); } + +function theme_blogclient_autodiscover($form) { + foreach (explode('|', $form['endpoints']['#value']) as $current_blogid) { + $row = array(); + foreach (array('defaultpost','title','endpoint','remote_id','type','save') as $key) { + $row[] = form_render($form[$key][$key.$current_blogid]); } - return drupal_get_form('blogclient_edit', $form); + $rows[] = $row; } + $buttons = ''; + foreach (array('next','delete') as $button) { + if ($form[$button]) { + $buttons .= form_render($form[$button]); + } + } + $output = ''; + $output .= form_render($form); + $output .= $buttons; + $output .= theme('table', array(t('Default'), t('Name'), t('API URL'), $endpoint['type'] == 'atom' ? ' ' : t('Remote id'), t('Type'), t('Save?')), $rows); + return $output; +} -function blogclient_edit_submit($form_id, $form_values) { +function blogclient_autodiscover_submit($form_id, $form_values) { global $user; - if ($form_values['blogid']) { - db_query("UPDATE {blogs} SET url = '%s', name = '%s', pass = '%s', remote_id = '%s', type = '%s', title = '%s', endpoint = '%s' WHERE blogid = %d", $form_values['url'], $form_values['name'], $form_values['pass'], $form_values['remote_id'], $form_values['type'], $form_values['title'], $form_values['endpoint'], $form_values['blogid']); + $blogid = arg(3); + if ($blogid) { + foreach (explode('|', $form_values['endpoints']) as $current_blogid) { + db_query("UPDATE {blogs} SET url = '%s', name = '%s', pass = '%s', remote_id = '%s', type = '%s', title = '%s', endpoint = '%s', defaultpost = %d WHERE blogid = %d", + $form_values['url'], $form_values['name'], $form_values['pass'], $form_values['remote_id'.$current_blogid], $form_values['type'.$current_blogid], $form_values['title'.$current_blogid], $form_values['endpoint'.$current_blogid], $form_values['defaultpost'.$current_blogid], $current_blogid); + } } else { + foreach (explode('|', $form_values['endpoints']) as $current_blogid) { $blogid = db_next_id('{blogs}_blogid'); - db_query("INSERT INTO {blogs} (blogid, url, name, pass, remote_id, type, uid, title, endpoint) VALUES (%d, '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s')", $blogid, $form_values['url'], $form_values['name'], $form_values['pass'], $form_values['remote_id'], $form_values['type'], $user->uid, $form_values['title'], $form_values['endpoint']); + db_query("INSERT INTO {blogs} (blogid, url, name, pass, remote_id, type, uid, title, endpoint, defaultpost) VALUES (%d, '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', %d)", + $blogid, $form_values['url'], $form_values['name'], $form_values['pass'], $form_values['remote_id'.$current_blogid], $form_values['type'.$current_blogid], $user->uid, $form_values['title'.$current_blogid], $form_values['endpoint'.$current_blogid], $form_values['defaultpost'.$current_blogid]); } - return 'blogclient'; + } + return 'syndicate/blog'; } function _blogclient_discover($url, $name, $pass) { $data = _blogclient_discover_curl($url, $name, $pass); - $links = preg_match_all('//U', $data, $m); + if ($data == -401) { + return -401; + } + preg_match_all('//U', $data, $m); $atom_feed_count = 0; $atom_post_links = array(); $blogapi_links = array(); foreach ($m[0] as $link) { $processed_link = _blogclient_discover_process($link); if ($processed_link['type'] == 'application/rsd+xml') { - $blogapi_links = _blogclient_discover_rsd($processed_link['href']); + $blogapi_links = _blogclient_discover_rsd($processed_link['href'], $name, $pass); } if ($processed_link['type'] == 'application/atom+xml') { if ($processed_link['rel'] == 'service.post') { @@ -183,22 +365,38 @@ if ($n > 1 && $n != $atom_feed_count) { // this is for blogger.com $false_atom_post_links = $atom_post_links; $atom_post_links = array(); + $failed_counter = 0; foreach ($false_atom_post_links as $blog) { $return = _blogclient_discover($blog['endpoint'], $name, $pass); - $atom_post_links = array_merge($atom_post_links, $return['atom_post_links']); + if ($return == -401) { + $failed_counter++; } + else { + $atom_post_links = array_merge($atom_post_links, $return['atom']); } - return array('blogapi_links' => $blogapi_links, 'atom_post_links' => $atom_post_links); + } + if ($failed_counter == count($false_atom_post_links)) { + return -401; + } + } + $return = array(); + if (!empty($atom_post_links)) { + $return['atom'] = $atom_post_links; + } + return array_merge($return, $blogapi_links); } function blogclient_discover($url, $name, $pass) { $links = _blogclient_discover($url, $name, $pass); - $endpoints = array_merge($links['blogapi_links'], $links['atom_post_links']); - foreach (array('atom', 'metaweblog', 'blogger') as $type) { - foreach ($endpoints as $endpoint) { - if ($endpoint['type'] == $type) { - return $endpoint; + if ($blogs = blogclient_discover_blogs($links, $name, $pass)) { + $links = $blogs; } + if ($links == -401) { + return -401; + } + foreach (array('atom', 'metaweblog', 'blogger') as $type) { + if (isset($links[$type])) { + return $links[$type]; } } } @@ -206,60 +404,109 @@ function _blogclient_discover_curl($url, $name = '', $pass = '') { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_TIMEOUT, 4); - if ($name) { - curl_setopt($ch, CURLOPT_USERPWD, $name .':'. $pass); - } curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE); curl_setopt($ch, CURLOPT_MAXREDIRS, 2); + curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)'); + if ($name) { + if ($url[4] == 's') { + curl_setopt($ch, CURLOPT_USERPWD, "$name:$pass"); + } + else { + curl_setopt($ch, CURLOPT_HTTPHEADER, blogclient_wsse_headers($name, $pass)); + } + } $data = curl_exec($ch); if (curl_errno($ch)) { return FALSE; } + $return_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if ($return_code == 401) { + return -401; + } + curl_close($ch); return $data; } function _blogclient_discover_process($tag) { $processed_tag = array(); - preg_match_all('/ ([^=]+)=([\'"])([^\'"]+)\2/', $tag, $m, PREG_SET_ORDER); + preg_match_all('/ ([^=]+)="([^"]+)"/', $tag, $m, PREG_SET_ORDER); foreach ($m as $attr) { - $processed_tag[$attr[1]] = $attr[3]; + $processed_tag[$attr[1]] = $attr[2]; } return $processed_tag; } -function _blogclient_discover_rsd($url) { +function _blogclient_discover_rsd($url, $name, $pass) { $data = _blogclient_discover_curl($url); preg_match('|(.*)|', $data, $m); $title = $m[1]; - $api = preg_match_all('//U', $data, $m); + preg_match_all('//U', $data, $m); $endpoints = array(); $possible_apis = array('blogger', 'metaweblog'); foreach ($m[0] as $api) { $processed_api = _blogclient_discover_process($api); $possible_api = strtolower($processed_api['name']); if (isset($possible_apis)) { - $endpoints[] = array('endpoint' => $processed_api['apiLink'], 'type' => $possible_api, 'remote_id' => $processed_api['blogID'], 'title' => $title); + $endpoints[$possible_api][] = array('endpoint' => $processed_api['apiLink'], 'type' => $possible_api, 'remote_id' => $processed_api['blogID'], 'title' => $title); } } return $endpoints; -// +} + +function blogclient_discover_blogs($links, $name, $pass) { + $blogs = array(); + foreach (array('atom', 'metaweblog', 'blogger') as $type) { + if (isset($links[$type])) { + if ($type == 'atom') { + foreach ($links['atom'] as $endpoint) { + // remove last part of URL + $data = _blogclient_discover_curl(preg_replace('!/[^/]+/?$!', '', $endpoint['endpoint']), $name, $pass); + if ($data == -401) { + return -401; + } + if (preg_match_all('//U', $data, $m)) { + $atom_post_links = array(); + foreach ($m[0] as $link) { + $processed_link = _blogclient_discover_process($link); + if ($processed_link['type'] == 'application/atom+xml' && $processed_link['rel'] == 'service.post') { + $blogs['atom'][] = array('endpoint' => $processed_link['href'], 'type' => 'atom', 'remote_id' => '', 'title' => $processed_link['title']); + } + } + } + } + } + else { + foreach ($links[$type] as $endpoint) { + $result = xmlrpc($endpoint['endpoint'], 'blogger.getUsersBlogs', '0123456789ABCDEF', $name, $pass); + if (is_array($result)) { + foreach ($result as $blog) { + $type = $endpoint['type']; + $blogs[$type][] = array('endpoint' => $endpoint['endpoint'], 'type' => $type, 'remote_id' => $blog['blogid'], 'title' => $blog['blogName']); + } + } + elseif (xmlrpc_errno() == 3001 || strpos(strtolower(xmlrpc_error_msg()), 'password') !== FALSE) { + return -401; + } + } + } + } + } + return $blogs; } function blogclient_nodeapi($node, $op) { global $user; switch ($op) { case 'insert': - case 'update': foreach ($node->blogs as $blogid) { - $ret = blogclient_post_node($node->nid, $blogid); - if ($ret !== TRUE) { - drupal_set_message(t('blogclient: %errormessage', array('%errormessage'=>$ret)), 'error'); - } + blogclient_post_node($node->nid, $blogid); } break; + /* FIXME - keep track of any posted ID and do an updated on update */ + // case 'update': } } @@ -285,20 +532,17 @@ global $user; $node = node_load(array('nid' => $nid)); $blog = db_fetch_object(db_query('SELECT * FROM {blogs} WHERE blogid = %d AND uid = %d', $blogid, $user->uid)); // uid only for safety - $function = '_blogclient_'. $blog->type .'_post_node'; + $function = '_blogclient_'. blogclient_type_map($blog->type) .'_post_node'; if (function_exists($function)) { return $function($node, $blog); } } function _blogclient_atom_post_node($node, $blog) { - $headers = array("Content-type: application/atom+xml"); $issued = gmdate("Y-m-d\TH:i:s\Z", time()); $title = $node->title; - $body = $node->body ? $node->body : $node->details; - $body = str_replace(array('[q]', '[/q]'), '', $body); $blog_id = $blog->remote_id; - /* FIXME */ + $body = $node->body; $generator_url = 'http://nowpublic.com'; $generator = 'NowPublic.com'; @@ -313,26 +557,55 @@ CONTENT; - // Use curl to post to your blog. $ch = curl_init(); + if ($blog->endpoint[4] == 's') { + curl_setopt($ch, CURLOPT_USERPWD, "$blog->name:$blog->pass"); + $headers = array(); + } + else { + $headers = blogclient_wsse_headers($blog->name, $blog->pass); + } + $headers[] = "Content-type: application/atom+xml"; curl_setopt($ch, CURLOPT_URL, $blog->endpoint); // "https://www.blogger.com/atom/". $blog_id curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 4); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - curl_setopt($ch, CURLOPT_USERPWD, $blog->name .':'. $blog->pass); curl_setopt($ch, CURLOPT_POSTFIELDS, $content); $data = curl_exec($ch); $result = curl_errno($ch) ? curl_error($ch) : TRUE; + watchdog('blogclient', t("Posted to %endpoint, result is %result", array('%endpoint' => $blog->endpoint, '%result' => check_plain($data)))); return $result; } function _blogclient_blogger_post_node($node, $blog) { - $body = $node->body ? $node->body : $node->details; - xmlrpc($blog->endpoint, 'blogger.newPost', '0123456789ABCDEF', $blog->remote_id, $blog->name, $blog->pass, "$node->title$body", TRUE); - return xmlrpc_errno() ? xmlrpc_error_msg() : TRUE; + $result = xmlrpc($blog->endpoint, 'blogger.newPost', '0123456789ABCDEF', $blog->remote_id, $blog->name, $blog->pass, $node->body, TRUE); + watchdog('blogclient', t("Posted to %endpoint, result is %result, error is %error", array('%endpoint' => $blog->endpoint, '%result' => check_plain($result), 'error' => xmlrpc_error_msg()))); } + function _blogclient_metaweblog_post_node($node, $blog) { - $body = $node->body ? $node->body : $node->details; - xmlrpc($blog->endpoint, 'metaWeblog.newPost', $blog->remote_id, $blog->name, $blog->pass, array('title' => $node->title, 'description' => $body), TRUE); - return xmlrpc_errno() ? xmlrpc_error_msg() : TRUE; + $result = xmlrpc($blog->endpoint, 'metaWeblog.newPost', $blog->remote_id, $blog->name, $blog->pass, array('title' => $node->title, 'description' => $node->body), TRUE); + watchdog('blogclient', t("Posted to %endpoint, result is %result, error is %error", array('%endpoint' => $blog->endpoint, '%result' => check_plain($result), '%error' => xmlrpc_error_msg()))); +} + +function blogclient_wsse_headers($name, $pass) { + $timestamp = gmdate('Y-m-d\TH:i:s\Z'); + $nonce = md5(microtime()); + $digest = base64_encode(pack("H*", sha1($nonce . $timestamp . $pass))); + $wsse_array = array( + 'Username' => $name, + 'PasswordDigest' => $digest, + 'Nonce' => base64_encode($nonce), + 'Created' => $timestamp, + ); + $wsse = 'X-WSSE: UsernameToken '; + foreach ($wsse_array as $k => $v) { + $wsse .= $k .'="'. $v .'"'; + if ($k != 'Created') { + $wsse .= ', '; + } + } + return array( + 'Authorization: WSSE profile="UsernameToken"', + $wsse + ); }