Science And Technology


If you're sure you have ffmpeg installed on your linux box but you're still getting "Could not convert video" messages from your jomsocial cron you may want to check what exactly the output of your ffmpeg is in the linux terminal.
Go to your shell or linux terminal and type >/usr/bin/ffmpeg
You should get a bunch of output if ffmpeg is installed.
The important thing to notice here is the php code inside of jomsocial.
inside of com_community/libraries/videos.php You'll find the following code.
$hasVersion = JString::strpos( $output, 'FFmpeg version' );
$hasCopyright = JString::strpos( $output, 'the FFmpeg developers' );
return ($hasVersion !== false || $hasCopyright !== false);
This code is checking against the same output you get when you type ffmpeg into the terminal. My linux install was ubuntu 11.10 and my output was a lower case "ffmpeg version" and "the libdev developers" instead of capitalized "FFmpeg developers" and "the FFmpeg developers"
So make sure you check against the actual output of your ffmpeg instead of what jomsocial is checking against.

During my upgrade I had to upgrade my file downloader as well. I had to go through the atrocious task of testing paypals ipn functions and make sure they're working correctly. This turned out to be a huge headache. Apparently paypal sandbox doesn't send back a VERIFIED string anymore even if you're IPN listener is correctly configured and responding correctly. I spent hours last night stepping through the IPN procedure trying to figure out why the IPN was always failing.

After several hours of googling and coming across several official paypal instruction pages that contradict one another. Here's one that even contradicts itself. You'll notice that in the instructions of the page they say to post back the ipn data to www.paypal.com or www.sandbox.paypal.com, depending on whether you are going live or testing your listener in the Sandbox. But then lower on the page they provide a sample script and in that script they're posting to ssl://www.paypal.com WTF!!!

  • https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_admin_IPNImplementation
At least now I know that ssl://www.paypal.com is incorrect and www.paypal.com or www.sandbox.paypal.com is the correct url to post paypals ipn data back to , not like it matters because the sandbox mode never returns a "VERIFIED" string anyway.

Something else that may trip you up in sandbox ipn testing is, if you choose web accept in the ipn simulator it defaults to payment_status=Completed. Now here is a quote from paypal's instructions.

Lets look at web_accept it's the most common used and easiest to work with... web_accept performs 5 data checks before it processes anything. These checks are the minimum recommended by PayPal that should be performed in your as follows:

  1. Is status = Completed If its a new transaction then the status should not be Complete, if 'payment_status' => 'Completed', then its not new and we've already processed this, so the script will return false, trigger a fail message and NOT process.
  2. We have not already processed the subcribe or unsubscribe for this subscr_id When 'payment_status' => '', then we'll do another check to really make sure we haven't processed this transaction before. If we have then the value returned by 'txn_id' will be found in the database table #_ajp_orders_subscription_payments and the script will return false, trigger a fail message and NOT process.
  3. The reciever e-mail account is ours. This checks that the Admin Email address recorded in PaymentsPlus > General Settings > Mosets Tree > PayPal Admin Email matches the email returned by 'receiver_email' if it doesn't then the script will return a fail message for this item but still process.
  4. That payment amount is correct A clever script kiddie can manipulate the values in a payment button and try to get the item for less that its real value, so this will check the value being returned by 'mc_gross' and compare it with the value stored in the database, if it doesn't match then the script will return a fail message for this item showing both the stored and returned value but still process. If there's a discrepancy here then you need to discuss it with your user and take appropriate action, one of which could be reporting the violation to PayPal and suspending the listing.
  5. That the payment currency is correct Currency, is a bit fickle to get right, PayPal returns the currency from its own records in 'mc_currency', so this means that you must have this configured in your PayPal account at PayPal and then ensure that the currency matches your PayPal Account setting to that found in PaymentsPlus > Payment Gateway Settings > Currency code (under the PayPal Settings Configuration heading) if it dosen't match then the script will return a fail message for this item but still process.
So that basically says if you don't change the web accept payment_status variable from completed to something else, the ipn will not send back a "VERIFIED" string, not that it matters anyway because paypal's sandbox doesn't send a VERIFIED string anyway!!!

So what DOES paypal sandbox send back? Well the answer is literally nothing. Here, I'll show you.

HTTP/1.0 302 Found
Location: https://www.sandbox.paypal.com
Server: BigIP
Connection: close
Content-Length: 0
That's it. That's all they sand back in the sandbox. Screw BigIP. Should have named it BigTimeWaster.

So in closing here is a paypal ipn script that is adapted to the fact that the paypal sandbox ipn sucks donkey balls. In live mode of course paypal DOES send back the VERIFIED string that we want.

 
 
function validate_ipn() {
//live mode
$url = "www.paypal.com";
 
//if test mode
$url = "www.sandbox.paypal.com";
$path = "cgi-bin/webscr";
 
 
// generate the post string from the _POST vars aswell as load the
// _POST vars into an arry so we can play with them from the calling
// script.
$post_string = '';    
foreach ($_POST as $field=>$value) { 
       $this->ipn_data["$field"] = $value;
       $post_string .= $field.'='.urlencode(stripslashes($value)).'&'; 
}
$post_string.="cmd=_notify-validate"; // append ipn command
 
// open the connection to paypal
$fp = fsockopen($url,"80",$err_num,$err_str,30); 
if(!$fp) {
 
       // could not open the connection.  If loggin is on, the error message
       // will be in the log.
       $this->last_error = "fsockopen error no. $errnum: $errstr";
       $this->log_ipn_results(false);       
       return false;
 
} else { 
 
       // Post the data back to paypal
       fputs($fp, "POST " . $path . " HTTP/1.1\r\n"); 
       fputs($fp, "Host: " . $url . "\r\n"); 
       fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n"); 
       fputs($fp, "Content-length: ".strlen($post_string)."\r\n"); 
       fputs($fp, "Connection: close\r\n\r\n"); 
       fputs($fp, $post_string . "\r\n\r\n"); 
 
       // loop through the response from the server and append to variable
       while(!feof($fp)) { 
              $this->ipn_response .= fgets($fp, 1024); 
       } 
 
       fclose($fp); // close connection
 
}
 
 
if (eregi("VERIFIED",$this->ipn_response) || $url == 'www.sandbox.paypal.com') {
//if(true){  
       // Valid IPN transaction.
       $this->logThis('SUCCESS!!');
       //$this->log_ipn_results(true);
       return true;       
 
} else {  
       // Invalid IPN transaction.  Check the log for details.
       $this->logThis('IPN Validation Failed.');
       //$this->log_ipn_results(false);   
       return false;
 
}
}
 
function logThis($string)
{
    ob_start();
    print_r($string);
    $message = ob_get_clean();
 
    //put the file in the root for testing purposes. 
    $f = fopen(JPATH_ROOT . DS . 'test.txt','a');
    fwrite($f,$message);
    fclose($f);    
}
 
 

I downloaded this, but it didn't work with my version of agora 3.0.13 So I wrote the following script to do the migration. This script only works one topic/thread at a time. So you'll have to create your categories in kunena first. I only had about 7-8 categories in agora so I didn't write a script for that. Anyways, in order to use this you just need to change the id for t.forum_id to match the agora category/forum then change the $cat_id variable to match your new kunena category. Maybe someone else might need it.
 
//enter your database credentials here.
$host = "";
$user = "";
$pass = "";
$db = "";
 
$link = mysql_connect($host,$user,$pass) or die(mysql_error());
mysql_selectdb($db,$link) or die(mysql_error());
 
//get the total thread count so we know where to start inserting posts.
$sql = "SELECT COUNT(id) AS total FROM j17_kunena_messages";
$res = mysql_query($sql) or die(mysql_error());
$res = mysql_fetch_object($res);
$thread = $res->total+1;
 
//manually change the t.forum_id to match the agora forum id. (forums are categories in kunena)
//manually change the table prefix as well. 
//t.forum_id = agora_topics.forum_id
$sql = "
SELECT p.message, p.poster AS mes_poster, t.poster AS topic_poster, t.subject, u.id AS user_id, u.email, p.posted, t.num_views
FROM j15_agora_topics AS t
LEFT JOIN j15_agora_posts AS p ON p.topic_id = t.id
LEFT JOIN j15_users AS u ON u.username = p.poster
WHERE t.forum_id = 6
ORDER BY p.topic_id ASC
";
 
//manually change the cat_id to match the category id from kunena
//cat_id == kunena_messages table
$cat_id = 10;
$parent_id = 0;
$subject = '';
$i = $thread;
$res = mysql_query($sql) or die(mysql_error());
while($row = mysql_fetch_object($res))
{        
        if($row->subject != $subject && $i != 0)
        {
            $thread = $i;
            $parent_id = 0;            
        }
 
        $sql = "INSERT INTO j17_kunena_messages VALUES (0, ".$parent_id.", ".$thread.", ".$cat_id.", '".$row->poster."', ".$row->user_id.", '".$row->email."', '".mysql_escape_string($row->subject)."', ".$row->posted.", 0, 0, 0, 0, 0, ".$row->num_views.", 0, NULL, NULL, NULL)";
 
        echo $sql;
        mysql_query($sql) or die(mysql_error());
        $id = mysql_insert_id();
        //if($parent_id == 0)
        $sql = "INSERT INTO j17_kunena_messages_text VALUES (".$id.", '".mysql_escape_string($row->message)."')";
 
 
        mysql_query($sql) or die(mysql_error());
        echo $sql . "";
    if($parent_id == 0)
        $parent_id = $id;    
    $subject = $row->subject;
    $i++;
}
 
echo $thread;
mysql_close();
 

OOPS! I messed up!

You'll want this script to reset your kunena tables if you mess up. After you're finished go to the back end of kunena and recount the categories.
 
DROP TABLE j17_kunena_messages;
DELETE FROM j17_kunena_messages_text;
 
CREATE TABLE IF NOT EXISTS `j17_kunena_messages` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `parent` INT(11) DEFAULT '0',
  `thread` INT(11) DEFAULT '0',
  `catid` INT(11) NOT NULL DEFAULT '0',
  `name` tinytext,
  `userid` INT(11) NOT NULL DEFAULT '0',
  `email` tinytext,
  `subject` tinytext,
  `time` INT(11) NOT NULL DEFAULT '0',
  `ip` VARCHAR(15) DEFAULT NULL,
  `topic_emoticon` INT(11) NOT NULL DEFAULT '0',
  `locked` tinyint(4) NOT NULL DEFAULT '0',
  `hold` tinyint(4) NOT NULL DEFAULT '0',
  `ordering` INT(11) DEFAULT '0',
  `hits` INT(11) DEFAULT '0',
  `moved` tinyint(4) DEFAULT '0',
  `modified_by` INT(7) DEFAULT NULL,
  `modified_time` INT(11) DEFAULT NULL,
  `modified_reason` tinytext,
  PRIMARY KEY  (`id`),
  KEY `thread` (`thread`),
  KEY `ip` (`ip`),
  KEY `userid` (`userid`),
  KEY `time` (`time`),
  KEY `locked` (`locked`),
  KEY `hold_time` (`hold`,`time`),
  KEY `parent_hits` (`parent`,`hits`),
  KEY `catid_parent` (`catid`,`parent`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=0 ;
 
 
 

This tutorial is written in C# and will address the following:

  1. Finding window handles using the .NET System.Diagnostics.Process class.

  2. Accessing a separate and completely independent application via the Win32 API using the handles we gathered. ( in this case we will be using !Yahoo Messenger)

  3. Gain access to a child window of the independent application and manipulate it (send a string or press a button) by passing a byte array.( in this case the child window will be the send message text box and the send message send button.)

//We'll need to import the System.Diagnostics library so we can access the Process class.

using System.Diagnostics;

 

//These methods are imported in from the user32.dll. I recommend putting them in a separate class under the same

//namespace in order to avoid cluttering up your code.

[DllImport("user32.dll")]

 public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, IntPtr windowTitle);

[DllImport("user32.dll", SetLastError = true)]

public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

 

[DllImport("user32.dll")]

public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, IntPtr lParam);

 

[DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, StringBuilder lParam);

 

[DllImport("user32.dll")] public static extern uint SendMessage(IntPtr hWnd, uint MSG, uint zero, byte[] text);

 

[DllImport("user32.dll")] public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);

/// Win32 SDK constants

/// </summary>

public const uint WM_SETTEXT = 0x000C;

public const uint WM_GETTEXT = 0x000D;

public const uint EM_SETSEL = 0x000000B1;

public const uint WM_GETTEXTLENGTH = 0x000E;

public const uint SMTO_ABORTIFHUNG = 0x0002;

public const int BM_CLICK = 0x00F5;

 

//We will call this method whenever we want to send a message to Yahoo Messenger from our application

public void PostToMessengerChat()

{

//you can find the name of the process that owns the windows you are trying to access by

//accessing the task-manager. Then load a process array with the following line.

Process[] processes = Process.GetProcessesByName("YahooMessenger");

//Declare a null window handle called hwnd.

IntPtr hwnd = IntPtr.Zero;

//Declare a null window handle called mainHand

IntPtr mainHand = IntPtr.Zero;

//Iterate through the process array until we find the window we want

foreach (Process p in processes)

{

//get WindowTitle and check it's the one you want

String checkString = p.MainWindowTitle;

//all !Yahoo chat rooms end with this patternString

String patternString = "-- Chat";

 

if (checkString.Contains(patternString))

{

//the pattern matches ! This is the window we want. Get it's handle.

mainHand = p.MainWindowHandle;

}

}

//find the class name of the child window using spy++ (YIMInputWindow)

//this function returns the handle of the window that matches the class name string.

IntPtr childWindow = Win32API.FindWindowEx(mainHand, IntPtr.Zero, "YIMInputWindow", IntPtr.Zero);

//WM_GETTEXTLENGTH - get the length of the users text in the text input window text if there is any

int textLength = Win32API.SendMessage(childWindow, Win32API.WM_GETTEXTLENGTH, 0, IntPtr.Zero);

//create a StringBuilder to hold users text input StringBuilders are {Zero Based}

StringBuilder writingtext = new StringBuilder(textLength + 1);

//WM_GETTEXT - sendmessage with a stringbuilder arg and length arg returns a stringbuilder that contains the

//current text in the YIMInputWindow. This is, so that when we send our message it doesnt mess up the current

//users text if they happen to be typing. This part is a bit weird because the method loads the stringbuilder

//yet we never assign it. By passing the stringbuilder to this method our result is a stringbuilder containing

//the users current text.

Win32API.SendMessage(childWindow, Win32API.WM_GETTEXT, textLength + 1, writingtext);

 

//create a byte array of the string we will be sending, in this case it is the currently playing MP3.

byte[] encryptedText_byte = System.Text.Encoding.ASCII.GetBytes((": hears: " +

playList.Items[currentSongNumber]).ToCharArray());

 

//WM_SETTEXT - send our song string byteArray

Win32API.SendMessage(childWindow, Win32API.WM_SETTEXT, 0, encryptedText_byte);

//find the send buttons window handle

IntPtr buttonWindow = Win32API.FindWindowEx(mainHand, IntPtr.Zero, "Button", "&Send");

//BM_CLICK - click the button to send the song message to the chat

Win32API.SendMessage(buttonWindow, Win32API.BM_CLICK, 0, encryptedText_byte);

//WM_SETTEXT - put the users current text back to it's original place

encryptedText_byte = System.Text.Encoding.ASCII.GetBytes((writingtext.ToString()).ToCharArray());

Win32API.SendMessage(childWindow, Win32API.WM_SETTEXT, 0, encryptedText_byte);

//WM_SETSEL - put the cursor at the end of the users text so they can keep typing

Win32API.SendMessage(childWindow, Win32API.EM_SETSEL, writingtext.Length, writingtext.Length);

}

Your feedback is welcome.

Page 1 of 3