Only in ../twitter: .DS_Store
Only in ../twitter: CHANGELOG.txt
Only in ../twitter: scheduled-tweets-6.patch
Only in ../twitter: twitter.api.php
diff -rup ../../../../../modules/twitter-old/twitter.inc ../twitter/twitter.inc
--- ../../../../../modules/twitter-old/twitter.inc	2011-01-19 17:43:40.000000000 -0500
+++ ../twitter/twitter.inc	2011-01-18 20:23:23.000000000 -0500
@@ -46,6 +46,13 @@ function twitter_account_save($twitter_u
   }
 }
 
+//load twitter account id from user id
+function twitter_get_twitter_id($uid) {
+ return db_result(db_query("SELECT twitter_uid FROM {twitter_account} WHERE uid= %d", $uid));
+}
+
+
+//take twitter id and returns twitter account
 function twitter_account_load($id) {
   module_load_include('lib.php', 'twitter');
 
@@ -79,12 +86,20 @@ function twitter_status_save($status) {
 
 /**
  * Post a message to twitter
+ * Returns true or false on success or failure
  */
+ //TODO: needs to return false if it fails, true if not.
 function twitter_set_status($twitter_account, $status) {
   module_load_include('lib.php', 'twitter');
 
   $twitter = twitter_connect($twitter_account);
-  $twitter->status_update($status);
+  $twitter_status_post_success = $twitter->status_update($status);
+  if ($twitter_status_post_success->created_at) {
+    return TRUE;
+  }
+  else {
+   return FALSE; 
+  }
 }
 
 /**
diff -rup ../../../../../modules/twitter-old/twitter.install ../twitter/twitter.install
--- ../../../../../modules/twitter-old/twitter.install	2011-01-19 17:43:40.000000000 -0500
+++ ../twitter/twitter.install	2011-01-18 01:06:45.000000000 -0500
@@ -692,4 +692,6 @@ function twitter_update_6300() {
 function twitter_uninstall() {
   // Remove tables.
   drupal_uninstall_schema('twitter');
+	// remove twitter status variables with nids in them created by twitter_post for unpublished nodes
+	db_query("DELETE FROM `variable` WHERE `name` LIKE 'twitter-node-status-%';");
 }
diff -rup ../../../../../modules/twitter-old/twitter_actions/twitter_actions.module ../twitter/twitter_actions/twitter_actions.module
--- ../../../../../modules/twitter-old/twitter_actions/twitter_actions.module	2011-01-19 17:43:40.000000000 -0500
+++ ../twitter/twitter_actions/twitter_actions.module	2011-01-16 16:16:30.000000000 -0500
@@ -170,5 +170,13 @@ function twitter_actions_set_status_acti
 
   module_load_include('inc', 'twitter');
   $twitter_account = twitter_account_load($context['twitter_uid']);
-  twitter_set_status($twitter_account, $message);
+  //TODO, make log message more useful
+  if (twitter_set_status($twitter_account, $message)){
+   //do something useful.  should this be logged to watchdog?
+  }
+  else {
+    $logging_array = array('%message'=>$message, '%uid'=>$$context['twitter_uid'], '%status_length'=>$status_length);
+    watchdog('twitter',"Tweet %message not posted for user id %user because posting failed.  Check message length.", $logging_array, WATCHDOG_WARNING);
+  }
+  
 }
diff -rup ../../../../../modules/twitter-old/twitter_post/twitter_post.module ../twitter/twitter_post/twitter_post.module
--- ../../../../../modules/twitter-old/twitter_post/twitter_post.module	2011-01-19 17:43:40.000000000 -0500
+++ ../twitter/twitter_post/twitter_post.module	2011-01-21 00:06:00.000000000 -0500
@@ -57,8 +57,23 @@ function twitter_post_form_alter(&$form,
       '#default_value' => (empty($form['nid']['#value'])),
       '#id' => 'twitter-toggle',
     );
+    //check if this has a nid, that is, is it a saved node, possibly unpublished
+    //note: only previously saved nodes could have saved statuses
+    $saved_status = NULL; //ensure $saved status exists outside scope of if
+    if($nid = $form['nid']['#value']){
+      $saved_status_array = twitter_post_get_saved_status($nid);
+      $saved_status = $saved_status_array['status'];
+    }
     $form['twitter'] += $twitter_form;
-    $form['twitter']['status']['#default_value'] = variable_get('twitter_post_default_format', 'New post: !title !tinyurl');
+    if ($saved_status || !empty($form['twitter']['status'])) {
+      if ($saved_status){
+        $form['twitter']['status']['#default_value'] = $saved_status;
+      }
+      $form['twitter']['post']['#default_value'] = TRUE;
+    }
+    elseif (!empty($form['twitter']['status'])) {
+      $form['twitter']['status']['#default_value'] = variable_get('twitter_post_default_format', 'New post: !title !tinyurl');
+    }
     $form['twitter']['status']['#description'] = t('The given text will be posted to twitter.com. You can use !url, !url-alias, !tinyurl, !title and !user as replacement text.');
   }
 }
@@ -66,41 +81,172 @@ function twitter_post_form_alter(&$form,
 /**
  * Implementation of hook_nodeapi().
  *
- * Intercepts newly published nodes and posts noticed to Twitter.
+ * Intercepts newly published nodes and posts notices to Twitter.
  */
+ 
 function twitter_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
-  
+  //declare this outside if so scope will last from validate to update, and !tinyurl doesn't need to be regenerated
+  $status_with_replacements_global = NULL;
   switch ($op) {
+    //make sure status isn't too long
+    //without substitutions, status can pass form char validation but fail post with substituions
+    case 'validate':
+      if (!empty($node->twitter['status']) && !empty($node->twitter['post'])) {
+        global $status_with_replacements_global;
+        //replace what can be replaced
+        $status_with_replacements_global = twitter_post_replace_tokens(&$node);
+        //attempt to calculate those things that could not be be replaced.
+        $status_length = twitter_post_calculate_length($status_with_replacements_global);
+        if ($status_length > 140) {
+          //save status on fail for later
+          module_load_include('inc', 'twitter');
+          $twitter_account = twitter_account_load($node->twitter['account']);
+          //bulld array to save
+          $status_array = array('status' => $status_with_replacements_global, 'account' => $node->twitter['account']);
+          //save status to variable in db
+          $logging_array = array('%status'=>$status, '%nid'=>$node->nid, '%status_length'=>$status_length);
+          form_set_error('twitter',t("Tweet %status not posted for node %nid because it was %status_length characters in length", $logging_array));
+          //log to watchdog in case this is a programmatic save (paranoid logging)
+          watchdog('twitter',"Tweet %status not posted for node %nid because, with substitutions, it was projected to be %status_length characters in length", $logging_array, WATCHDOG_WARNING);
+        }
+      }
+      break;
+      
     case 'insert':
+      twitter_post_update_or_insert(&$node);
+    break;
+    
     case 'update':
-      if (!empty($node->status) && !empty($node->twitter) && !empty($node->twitter['post'])) {
-        module_load_include('inc', 'twitter');
+      twitter_post_update_or_insert(&$node);
+    break;
+    
+    case 'delete':
+      twitter_post_delete_saved_status($node->nid);
+    break;
+    }
+}
 
-        $twitter_account = twitter_account_load($node->twitter['account']);
-        $replacements = array('!title' => $node->title,
-                              '!url' => url('node/'. $node->nid, array('absolute' => TRUE, 'alias' => TRUE)),
-                              '!url-alias' => url('node/'. $node->nid, array('absolute' => TRUE)),
-                              '!user' => $node->name);
-        // Only generate the shortened URL if it's going to be used. No sense
-        // burning through TinyURLs without a good reason.
-        if (strstr($node->twitter['status'], '!tinyurl') !== FALSE) {
-          $replacements['!tinyurl'] = twitter_shorten_url(url('node/'. $node->nid, array('absolute' => TRUE)));
-        }
+function twitter_post_update_or_insert(&$node) {
+  //if twitter array in form is empty, then node is submitted programatically
+  //if type is in twitter_post_types and twitter array is empty, check for a saved value
+  module_load_include('inc', 'twitter');
+  $allowed_post_types = variable_get('twitter_post_types',0);
+  if (empty($node->twitter['status']) && in_array($node->type, $allowed_post_types)) {
+   if ($saved_status_array = twitter_post_get_saved_status($node->nid)) {
+     $node->twitter['status'] = $saved_status_array['status'];
+     $node->twitter['post'] = 1;
+     $node->twitter['account'] = twitter_get_twitter_id($node->uid);
+    } 
+  }
+  //node submitted with an unchecked post value, we'll assume they want to delete saved status
+  elseif (empty($node->twitter['post'])) {
+    twitter_post_delete_saved_status($node->nid);
+  }
+  else { //this else is called on a non-programmatic submission
+    //grab the saved status from outside more universal scope which was set in the validate case above
+    global $status_with_replacements_global;
+    $node->twitter['status'] = $status_with_replacements_global;
+  }
 
-        $status = strtr($node->twitter['status'], $replacements);
-        try {
-          $result = twitter_set_status($twitter_account, $status);
-          drupal_set_message(t('Successfully posted to Twitter'));
-        }
-        catch (TwitterException $e) {
-          drupal_set_message(t('An error occurred when posting to twitter: %code %error',
-                               array('%code' => $result->code, '%error' => $result->error)), 'warning');
-        }
-      }
-      break;
+  module_load_include('inc', 'twitter');
+  
+  $twitter_account = twitter_account_load($node->twitter['account']);
+  $status_array = array('status' => $node->twitter['status'], 'account' => $node->twitter['account']); //we'll use this array in case posting fails later
+  if (empty($node->status) && !empty($node->twitter) && !empty($node->twitter['post'])) {
+    twitter_post_save_status_to_db($status_array, $node->nid);
   }
+
+  if (!empty($node->twitter) && !empty($node->twitter['post']) && !empty($node->status)) {
+    $twitter_account = twitter_account_load($node->twitter['account']); //load the account object
+    //before tweeting, url tokens may not have been replaced, so replace
+    $node->twitter['status'] = twitter_post_replace_tokens(&$node);
+    if ($result = twitter_set_status($twitter_account, $node->twitter['status'])) {
+      drupal_set_message(t('Successfully posted to Twitter'));
+      //delete saved status on success
+      twitter_post_delete_saved_status($node->nid);
+    }
+    else {
+      twitter_post_save_status_to_db($status_array, $node->nid); 
+      $logging_array = array('%status' => $node->twitter['status'], '%uid' => $node->uid);
+      drupal_set_message(t('An error occurred when posting to twitter.  Status: %status For user number: %uid',
+                           $logging_array), 'warning');
+      watchdog('twitter','An error occurred when posting to twitter.  Status: %status For user number: %uid', 
+              $logging_array, WATCHDOG_WARNING);
+    
+    }
+  } 
 }
 
+//take a status and return an estimated length
+function twitter_post_calculate_length($status) {
+  $length = strlen($status);
+  if (strstr($status,'!tinyurl')){
+    $average_tinyurl_length = 26;
+    $length += ($average_tinyurl_length - strlen('!tinyurl'));
+  }
+    
+  //it is not possible for this to be accurate because alias length is arbitrary, 
+  //therefore, we'll set a minumum and let the user screw it up if they want
+  if (strstr($status,'!url-alias')){
+    global $base_url;
+    //subtract length of string '!url-alias', 10
+    //add 2, the minimum possible url, ie http://yourdomain.com/a
+    $length += (strlen($base_url) + 2 - 10);
+    //remove !url-alias from status so it isn't matched by !url
+    $status = strtr($status, '!url-alias');
+  }
+   
+  if (strstr($status,'!url')){
+    //use largest nid in db to conjecture length of url.  Of course, this will be max_nid + 1 so this will sometimes fail.  
+    $max_nid = db_result(db_query('SELECT MAX(nid) AS nid FROM node'));
+    //subtract length of string '!url-alias', 4
+    $url = url('node/'. $max_nid, array('absolute' => TRUE, 'alias' => TRUE));
+    $length += (strlen($url) - 4);
+    //remove !url from s
+  }
+  
+  return $length; 
+}
+
+//return replaced status
+function twitter_post_replace_tokens(&$node){
+  $replacements = array('!title' => $node->title,
+                        '!user' => $node->name);
+  //if node can have url, that is, if it has nid.
+  if ($node->nid) {
+    $url_replacements = array('!url' => url('node/'. $node->nid, array('absolute' => TRUE, 'alias' => TRUE)),
+                                    '!url-alias' => url('node/'. $node->nid, array('absolute' => TRUE)));
+    // Only generate the shortened URL if it's going to be used. No sense generating unused tinurls                                
+    if (strstr($node->twitter['status'], '!tinyurl')) {
+     $url_replacements['!tinyurl'] = twitter_shorten_url(url('node/'. $node->nid, array('absolute' => TRUE))); 
+    }
+    $replacements = array_merge($replacements, $url_replacements);
+  }
+    
+  $status_with_replacements = strtr($node->twitter['status'], $replacements);
+  //if published set global for save in update hook.
+  return $status_with_replacements;
+}
+
+//takes a nid and an array of values to save
+//TODO: move this into a proper DB table and create an update for the db.
+function twitter_post_save_status_to_db($status_array, $nid){
+  $status_variable_name = 'twitter-node-status-'. $nid;
+  variable_set($status_variable_name, $status_array);
+}
+
+//delete saved status from the db, called on hook_nodeapi op delete
+function twitter_post_delete_saved_status($nid) {
+  $status_variable_name = 'twitter-node-status-'. $nid;
+  variable_del($status_variable_name);
+}
+
+//fetch status from db
+function twitter_post_get_saved_status($nid) {
+  $saved_status_var_name = 'twitter-node-status-'. $nid; 
+  $saved_status_array = variable_get($saved_status_var_name, 0);
+  return $saved_status_array;
+}
 
 /**
  * Generate a twitter posting form for the given user.
@@ -127,6 +273,7 @@ function twitter_post_form($account = NU
     $form['status'] = array(
       '#type' => 'textfield',
       '#id' => 'twitter-textfield',
+      '#maxlength' => 140,
     );
 
     if (count($options) > 1) {
@@ -145,4 +292,4 @@ function twitter_post_form($account = NU
     }
     return $form;
   }
-}
+}
\ No newline at end of file
