Index: autoload/ezp_kernel.php
===================================================================
--- autoload/ezp_kernel.php	(revision 24261)
+++ autoload/ezp_kernel.php	(working copy)
@@ -330,6 +330,7 @@
       'eZPublishSDK'                                       => 'lib/version.php',
       'eZPublishType'                                      => 'kernel/classes/notification/event/ezpublish/ezpublishtype.php',
       'eZRSSEditFunction'                                  => 'kernel/rss/edit_functions.php',
+      'eZRSSFunctionCollection'                            => 'kernel/rss/ezrssfunctioncollection.php',
       'eZRSSExport'                                        => 'kernel/classes/ezrssexport.php',
       'eZRSSExportItem'                                    => 'kernel/classes/ezrssexportitem.php',
       'eZRSSImport'                                        => 'kernel/classes/ezrssimport.php',
Index: design/admin/templates/content/view/versionview.tpl
===================================================================
--- design/admin/templates/content/view/versionview.tpl	(revision 24261)
+++ design/admin/templates/content/view/versionview.tpl	(working copy)
@@ -206,7 +206,7 @@
 
 {* DESIGN: Header START *}<div class="box-header"><div class="box-tc"><div class="box-ml"><div class="box-mr"><div class="box-tl"><div class="box-tr">
 
-<h1 class="context-title"><a href={concat( '/class/view/', $object.contentclass_id )|ezurl} onclick="ezpopmenu_showTopLevel( event, 'ClassMenu', ez_createAArray( new Array( '%classID%', {$object.contentclass_id},'%objectID%',{$object.id},'%nodeID%',{$node.node_id},'%currentURL%','{$node.url|wash( javascript )}')), '{$object.content_class.name|wash(javascript)}', -1 ); return false;">{$object.content_class.identifier|class_icon( normal, $node.class_name )}</a>&nbsp;{$object.name|wash}&nbsp;[{$object.content_class.name|wash}]</h1>
+<h1 class="context-title"><a href={concat( '/class/view/', $object.contentclass_id )|ezurl} onclick="ezpopmenu_showTopLevel( event, 'ClassMenu', ez_createAArray( new Array( '%classID%', {$object.contentclass_id},'%objectID%',{$object.id},'%nodeID%',{$node.node_id},'%currentURL%','{$node.url|wash( javascript )}')), '{$object.content_class.name|wash(javascript)}', ['class-addnodefeed', 'class-removenodefeed'] ); return false;">{$object.content_class.identifier|class_icon( normal, $node.class_name )}</a>&nbsp;{$object.name|wash}&nbsp;[{$object.content_class.name|wash}]</h1>
 
 {* DESIGN: Mainline *}<div class="header-mainline"></div>
 
Index: design/admin/templates/node/view/full.tpl
===================================================================
--- design/admin/templates/node/view/full.tpl	(revision 24268)
+++ design/admin/templates/node/view/full.tpl	(working copy)
@@ -15,9 +15,22 @@
 
 
 {def $js_class_languages = $node.object.content_class.prioritized_languages_js_array
-     $disable_another_language = cond( eq( 0, count( $node.object.content_class.can_create_languages ) ),"'edit-class-another-language'", '-1' ) }
+     $disable_another_language = cond( eq( 0, count( $node.object.content_class.can_create_languages ) ),"'edit-class-another-language'", '-1' )
+     $disabled_sub_menu = "['class-addnodefeed', 'class-removenodefeed']"}
 
-<h1 class="context-title"><a href={concat( '/class/view/', $node.object.contentclass_id )|ezurl} onclick="ezpopmenu_showTopLevel( event, 'ClassMenu', ez_createAArray( new Array( '%classID%', {$node.object.contentclass_id}, '%objectID%', {$node.contentobject_id}, '%nodeID%', {$node.node_id}, '%currentURL%', '{$node.url|wash( javascript )}', '%languages%', {$js_class_languages} ) ), '{$node.class_name|wash(javascript)}', -1, {$disable_another_language} ); return false;">{$node.class_identifier|class_icon( normal, $node.class_name )}</a>&nbsp;{$node.name|wash}&nbsp;[{$node.class_name|wash}]&nbsp;{$hide_status}</h1>
+{* Check if user has rights and if there are any RSS exports for current node *}
+{if is_set( ezini( 'RSSSettings', 'DefaultFeedItemClasses', 'site.ini' )[ $node.class_identifier ] )}
+    {def $create_rss_access = fetch( 'user', 'has_access_to', hash( 'module', 'rss', 'function', 'edit' ) )}
+    {if $create_rss_access}
+        {if fetch( 'rss', 'has_export_by_node', hash( 'node_id', $node.node_id ) )}
+            {set $disabled_sub_menu = "'class-addnodefeed'"}
+        {else}
+            {set $disabled_sub_menu = "'class-removenodefeed'"}
+        {/if}
+    {/if}
+{/if}
+
+<h1 class="context-title"><a href={concat( '/class/view/', $node.object.contentclass_id )|ezurl} onclick="ezpopmenu_showTopLevel( event, 'ClassMenu', ez_createAArray( new Array( '%classID%', {$node.object.contentclass_id}, '%objectID%', {$node.contentobject_id}, '%nodeID%', {$node.node_id}, '%currentURL%', '{$node.url|wash( javascript )}', '%languages%', {$js_class_languages} ) ), '{$node.class_name|wash(javascript)}', {$disabled_sub_menu}, {$disable_another_language} ); return false;">{$node.class_identifier|class_icon( normal, $node.class_name )}</a>&nbsp;{$node.name|wash}&nbsp;[{$node.class_name|wash}]&nbsp;{$hide_status}</h1>
 
 {undef $js_class_languages $disable_another_language}
 
Index: design/admin/templates/popupmenu/popup_menu.tpl
===================================================================
--- design/admin/templates/popupmenu/popup_menu.tpl	(revision 24261)
+++ design/admin/templates/popupmenu/popup_menu.tpl	(working copy)
@@ -81,6 +81,16 @@
 menuArray['ClassMenu']['elements']['view-cache-delete']['url'] = {"%currentURL%"|ezurl};
 menuArray['ClassMenu']['elements']['recursive-view-cache-delete'] = new Array();
 menuArray['ClassMenu']['elements']['recursive-view-cache-delete']['url'] = {"%currentURL%"|ezurl};
+menuArray['ClassMenu']['elements']['class-addnodefeed'] = new Array();
+menuArray['ClassMenu']['elements']['class-addnodefeed']['url'] = {"/content/view/full/%nodeID%"|ezurl};
+menuArray['ClassMenu']['elements']['class-addnodefeed']['disabled_class'] = 'menu-item-disabled';
+menuArray['ClassMenu']['elements']['class-addnodefeed']['disabled_for'] = new Array();
+menuArray['ClassMenu']['elements']['class-addnodefeed']['disabled_for']['class-addnodefeed'] = 'yes';
+menuArray['ClassMenu']['elements']['class-removenodefeed'] = new Array();
+menuArray['ClassMenu']['elements']['class-removenodefeed']['url'] = {"/content/view/full/%nodeID%"|ezurl};
+menuArray['ClassMenu']['elements']['class-removenodefeed']['disabled_class'] = 'menu-item-disabled';
+menuArray['ClassMenu']['elements']['class-removenodefeed']['disabled_for'] = new Array();
+menuArray['ClassMenu']['elements']['class-removenodefeed']['disabled_for']['class-removenodefeed'] = 'yes';
 menuArray['ClassMenu']['elements']['class-history'] = new Array();
 menuArray['ClassMenu']['elements']['class-history']['url'] = {"content/history/%objectID%"|ezurl};
 menuArray['ClassMenu']['elements']['url-alias'] = new Array();
@@ -249,6 +259,11 @@
 -->
     <a id="recursive-view-cache-delete" href="#" onmouseover="ezpopmenu_mouseOver( 'ClassMenu' )" onclick="ezpopmenu_submitForm( 'menu-form-recursive-view-cache-delete' ); return false;">{"Delete view cache from here"|i18n("design/admin/popupmenu")}</a>
     <hr />
+    <a id="class-addnodefeed" href="#" onmouseover="ezpopmenu_mouseOver( 'ClassMenu' )"
+       onclick="ezpopmenu_submitForm( 'menu-form-addnodefeed' ); return false;">{"Add node RSS feed"|i18n("design/admin/popupmenu")}</a>
+    <a id="class-removenodefeed" href="#" onmouseover="ezpopmenu_mouseOver( 'ClassMenu' )"
+       onclick="ezpopmenu_submitForm( 'menu-form-removenodefeed' ); return false;">{"Remove node RSS feed"|i18n("design/admin/popupmenu")}</a>
+    <hr />
     <a id="override-view" class="more" href="#" onmouseover="ezpopmenu_hide('OverrideByClassSiteAccess'); ezpopmenu_hide('OverrideByNodeSiteAccess'); ezpopmenu_showSubLevel( event, 'OverrideSiteAccess', 'override-view' ); return false;">{"Template overrides"|i18n("design/admin/popupmenu")}</a>
     <a id="override-by-class-view" class="more" href="#" onmouseover="ezpopmenu_hide('OverrideSiteAccess'); ezpopmenu_hide('OverrideByNodeSiteAccess'); ezpopmenu_showSubLevel( event, 'OverrideByClassSiteAccess', 'override-by-class-view' ); return false;">{"New class override"|i18n("design/admin/popupmenu")}</a>
     <a id="override-by-node-view" class="more" href="#" onmouseover="ezpopmenu_hide('OverrideSiteAccess'); ezpopmenu_hide('OverrideByClassSiteAccess'); ezpopmenu_showSubLevel( event, 'OverrideByNodeSiteAccess', 'override-by-node-view' ); return false;">{"New node override"|i18n("design/admin/popupmenu")}</a>
@@ -353,6 +368,20 @@
   <input type="hidden" name="NeedRedirectBack" value="x" />
 </form>
 
+{* Add node feed. *}
+<form id="menu-form-addnodefeed" method="post" action={"/content/action"|ezurl}>
+  <input type="hidden" name="ContentObjectID" value="%objectID%" />
+  <input type="hidden" name="NodeID" value="%nodeID%" />
+  <input type="hidden" name="EnableNodeFeed" value="x" />
+</form>
+
+{* Remove node feed *}
+<form id="menu-form-removenodefeed" method="post" action={"/content/action"|ezurl}>
+  <input type="hidden" name="ContentObjectID" value="%objectID%" />
+  <input type="hidden" name="NodeID" value="%nodeID%" />
+  <input type="hidden" name="DisableNodeFeed" value="x" />
+</form>
+
 {* Remove node. *}
 <form id="menu-form-remove" method="post" action={"/content/action"|ezurl}>
   <input type="hidden" name="TopLevelNode" value="%nodeID%" />
Index: design/admin/templates/rss/edit_export.tpl
===================================================================
--- design/admin/templates/rss/edit_export.tpl	(revision 24261)
+++ design/admin/templates/rss/edit_export.tpl	(working copy)
@@ -123,6 +123,7 @@
        <h2>{'Source'|i18n( 'design/admin/rss/edit_export' )} {sum($Source:index, 1)}</h2>
 
        <input type="hidden" name="Item_ID_{$Source:index}" value="{$Source:item.id}" />
+       <input type="hidden" name="Ignore_Values_On_Browse_{$Source:index}" id="Ignore_Values_On_Browse_{$Source:index}" value="{$Source:item.title|eq('')}" />
        <div class="block">
        <label>{'Source path'|i18n( 'design/admin/rss/edit_export' )}:</label>
        <input type="text" readonly="readonly" size="45" value="{$Source:item.source_path|wash}" />
@@ -131,12 +132,12 @@
        
         <div class="block">
         <label>{'Subnodes'|i18n( 'design/admin/rss/edit_export' )}:</label>
-        <input type="checkbox" name="Item_Subnodes_{$Source:index}" {if $Source:item.subnodes|wash|eq( 1 )}checked="checked"{/if} title="{'Activate this checkbox if objects from the subnodes of the source should also be fed.'|i18n('design/admin/rss/edit_export')}"/>
+        <input type="checkbox" name="Item_Subnodes_{$Source:index}" {if $Source:item.subnodes|wash|eq( 1 )}checked="checked"{/if} title="{'Activate this checkbox if objects from the subnodes of the source should also be fed.'|i18n('design/admin/rss/edit_export')}" onchange="document.getElementById('Ignore_Values_On_Browse_{$Source:index}').value=0;" />
         </div>
     
        <div class="block">
        <label>{'Class'|i18n( 'design/admin/rss/edit_export' )}:</label>
-       <select name="Item_Class_{$Source:index}" title="{'Use this drop-down to select the type of object that triggers the export. Click the "Set" button to load the correct attribute types for the remaining fields.'|i18n('design/admin/rss/edit_export')|wash}">
+       <select name="Item_Class_{$Source:index}" title="{'Use this drop-down to select the type of object that triggers the export. Click the "Set" button to load the correct attribute types for the remaining fields.'|i18n('design/admin/rss/edit_export')|wash}" onchange="document.getElementById('Ignore_Values_On_Browse_{$Source:index}').value=0;">
        {section name=ContentClass loop=$rss_class_array }
        <option
        {section name=Class show=eq( $:item.id, $Source:item.class_id )}
@@ -151,7 +152,7 @@
 
          <div class="block">
          <label>{'Title'|i18n( 'design/admin/rss/edit_export' )}:</label>
-         <select name="Item_Class_Attribute_Title_{$Source:index}" title="{'Use this drop-down to select the attribute that should be exported as the title of the RSS export entry.'|i18n('design/admin/rss/edit_export')}">
+         <select name="Item_Class_Attribute_Title_{$Source:index}" title="{'Use this drop-down to select the attribute that should be exported as the title of the RSS export entry.'|i18n('design/admin/rss/edit_export')}" onchange="document.getElementById('Ignore_Values_On_Browse_{$Source:index}').value=0;">
          {section name=ClassAttribute loop=$rss_export.item_list[$Source:index].class_attributes}
          <option value="{$:item.identifier}"
              {section name=ShowSelected show=eq( $Source:item.title, $:item.identifier )}
@@ -163,7 +164,7 @@
 
        <div class="block">
          <label>{'Description'|i18n( 'design/admin/rss/edit_export' )}:</label>
-         <select name="Item_Class_Attribute_Description_{$Source:index}" title="{'Use this drop-down to select the attribute that should be exported as the description of the RSS export entry.'|i18n('design/admin/rss/edit_export')}" >
+         <select name="Item_Class_Attribute_Description_{$Source:index}" title="{'Use this drop-down to select the attribute that should be exported as the description of the RSS export entry.'|i18n('design/admin/rss/edit_export')}" onchange="document.getElementById('Ignore_Values_On_Browse_{$Source:index}').value=0;">
          {section name=ClassAttribute loop=$rss_export.item_list[$Source:index].class_attributes}
          <option value="{$:item.identifier|wash}"
              {section name=ShowSelected show=eq( $Source:item.description, $:item.identifier )}
@@ -175,7 +176,7 @@
 
        <div class="block">
          <label>{'Category'|i18n( 'design/admin/rss/edit_export' )} ({'optional'|i18n( 'design/admin/rss/edit_export' )}):</label>
-         <select name="Item_Class_Attribute_Category_{$Source:index}" title="{'Use this drop-down to select the attribute that should be exported as the category of the RSS export entry.'|i18n('design/admin/rss/edit_export')}" >
+         <select name="Item_Class_Attribute_Category_{$Source:index}" title="{'Use this drop-down to select the attribute that should be exported as the category of the RSS export entry.'|i18n('design/admin/rss/edit_export')}" onchange="document.getElementById('Ignore_Values_On_Browse_{$Source:index}').value=0;">
          <option value="">[{'Skip'|i18n('design/admin/rss/edit_export')}]</option>
          {section name=ClassAttribute loop=$rss_export.item_list[$Source:index].class_attributes}
          <option value="{$:item.identifier|wash}"
Index: design/standard/javascript/popupmenu/ezpopupmenu.js
===================================================================
--- design/standard/javascript/popupmenu/ezpopupmenu.js	(revision 24261)
+++ design/standard/javascript/popupmenu/ezpopupmenu.js	(working copy)
@@ -146,7 +146,7 @@
 // Global VARS
 // CurrentNodeID holds id of current node to edit for submenu's
 var CurrentSubstituteValues = -1;
-var CurrentDisableID = -1;
+var CurrentDisableIDList = [];
 // Which Menu should be disabled
 var CurrentDisableMenuID = -1;
 
@@ -187,7 +187,7 @@
    'menuHeader' If the menu has a header it is replaced with this value.
    'disableID' If this id is found in the list of known disabled for this menu the item is disabled.
  */
-function ezpopmenu_showTopLevel( event, menuID, substituteValues, menuHeader, disableID, disableMenuID )
+function ezpopmenu_showTopLevel( event, menuID, substituteValues, menuHeader, disableIDList, disableMenuID )
 {
     if( !document.getElementById( menuID ) ) return;
     ezjslib_mouseHandler( event ); // register new mouse position
@@ -198,9 +198,9 @@
         CurrentSubstituteValues = substituteValues;
     }
 
-    if( disableID != -1 )
+    if( disableIDList != -1 )
     {
-        CurrentDisableID = disableID;
+    	CurrentDisableIDList = disableIDList.push !== undefined ? disableIDList : [disableIDList];
     }
 
     CurrentDisableMenuID = disableMenuID;
@@ -306,9 +306,18 @@
             hrefElement.innerHTML = content;
         }
 
-        if( ( typeof( menuArray[menuID]['elements'][i]['disabled_class'] ) != 'undefined' &&
-              ( ( typeof( menuArray[menuID]['elements'][i]['disabled_for'] ) != 'undefined' &&
-                  menuArray[menuID]['elements'][i]['disabled_for'][CurrentDisableID] == 'yes' ) ) ||
+        var disabledForElement = false;
+        if ( typeof( menuArray[menuID]['elements'][i]['disabled_for'] ) != 'undefined' && CurrentDisableIDList )
+        {
+        	for ( var disI = 0, disL = CurrentDisableIDList.length; disI < disL; disI++ )
+        	{
+        		if ( disabledForElement = menuArray[menuID]['elements'][i]['disabled_for'][ CurrentDisableIDList[disI] ] === 'yes'  )
+        			break;
+        	}
+        }
+
+        if ( typeof( menuArray[menuID]['elements'][i]['disabled_class'] ) != 'undefined' &&
+              ( disabledForElement ||
               ( CurrentDisableMenuID && hrefElement.id == CurrentDisableMenuID ) ) )
         {
             CurrentDisabledMenusItems[hrefElement.id] = new Array();
Index: kernel/content/action.php
===================================================================
--- kernel/content/action.php	(revision 24261)
+++ kernel/content/action.php	(working copy)
@@ -1259,6 +1259,60 @@
     {
         return $module->run( "collectinformation", array() );
     }
+    else if( $http->hasPostVariable( 'EnableNodeFeed' ) || $http->hasPostVariable( 'DisableNodeFeed' ) )
+    {
+        // First, do permission checking
+        $user = eZUser::currentUser();
+        $hasAccess = $user->hasAccessTo( 'rss', 'edit' );
+        if ( $hasAccess['accessWord'] === 'no' )
+        {
+            return $module->handleError( eZError::KERNEL_ACCESS_DENIED, 'kernel' );
+        }
+
+        // Then make sure we have node id parameter
+        if ( !$http->hasPostVariable( 'NodeID' ) )
+        {
+            eZDebug::writeError( 'Enable/ Disable NodeFeed: missing node ID parameter.', 'content-action-handler' );
+            return $module->handleError( eZError::KERNEL_NOT_AVAILABLE, 'kernel' );
+        }
+
+        $nodeID = $http->postVariable( 'NodeID' );
+        if ( $http->hasPostVariable( 'EnableNodeFeed' ) )
+        {
+            if ( eZOperationHandler::operationIsAvailable( 'content_createnodefeed' ) )
+            {
+                $operationResult = eZOperationHandler::execute( 'content',
+                                                                'createnodefeed', array( 'node_id' => $nodeID ),
+                                                                null,
+                                                                true );
+            }
+            else
+            {
+                $operationResult = eZContentOperationCollection::createFeedForNode( $nodeID );
+            }
+        }
+        else // DisableRSS
+        {
+            if ( eZOperationHandler::operationIsAvailable( 'content_removenodefeed' ) )
+            {
+                $operationResult = eZOperationHandler::execute( 'content',
+                                                                'removenodefeed', array( 'node_id' => $nodeID ),
+                                                                null,
+                                                                true );
+            }
+            else
+            {
+                $operationResult = eZContentOperationCollection::removeFeedForNode( $nodeID );
+            }
+        }
+
+        if ( !isset( $operationResult['status'] ) || !$operationResult['status'] )
+        {
+            return $module->handleError( eZError::KERNEL_NOT_AVAILABLE, 'kernel' );
+        }
+
+        return $module->redirectToView( 'view', array( 'full', $nodeID ) );
+    }
     else
     {
         $baseDirectory = eZExtension::baseDirectory();
Index: kernel/content/ezcontentoperationcollection.php
===================================================================
--- kernel/content/ezcontentoperationcollection.php	(revision 24261)
+++ kernel/content/ezcontentoperationcollection.php	(working copy)
@@ -320,7 +320,7 @@
             {
                 if ( $fromNodeID == 0 || $fromNodeID == -1 )
                 {
-                    eZDebug::writeError( "NodeAssignment '", $nodeAssignment->attribute( 'id' ), "' is marked with op_code='$opCode' but has no data in from_node_id. Cannot use it for moving node." );
+                    eZDebug::writeError( "NodeAssignment '" . $nodeAssignment->attribute( 'id' ) . "' is marked with op_code='$opCode' but has no data in from_node_id. Cannot use it for moving node.", __METHOD__ );
                 }
                 else
                 {
@@ -711,7 +711,7 @@
        if( !eZContentObjectTreeNodeOperations::move( $nodeID, $newParentNodeID ) )
        {
            eZDebug::writeError( "Failed to move node $nodeID as child of parent node $newParentNodeID",
-                                'content/action' );
+                                __METHOD__ );
 
            return array( 'status' => false );
        }
@@ -1229,7 +1229,7 @@
             if ( !$object->removeTranslation( $languageID ) )
             {
                 eZDebug::writeError( "Object with id $objectID: cannot remove the translation with language id $languageID!",
-                                     'content/translation' );
+                                     __METHOD__ );
             }
         }
 
@@ -1286,5 +1286,123 @@
     {
 
     }
+
+    /**
+    * Creates a rss export for a node
+    *
+    * @param int $nodeID Node ID
+    *
+    * @since 4.3
+    **/
+    static public function createFeedForNode( $nodeID )
+    {
+        $hasExport = eZRSSFunctionCollection::hasExportByNode( $nodeID );
+        if ( isset( $hasExport['result'] ) && $hasExport['result'] )
+        {
+            eZDebug::writeError( 'There is already a rss export feed for this node: ' . $nodeID, __METHOD__ );
+            return array( 'status' => false );
+        }
+
+        $node = eZContentObjectTreeNode::fetch( $nodeID );
+        $currentClassIdentifier = $node->attribute( 'class_identifier' );
+
+        $config = eZINI::instance( 'site.ini' );
+        $feedItemClasses = $config->variable( 'RSSSettings', 'DefaultFeedItemClasses' );
+
+        if ( !$feedItemClasses || !isset( $feedItemClasses[ $currentClassIdentifier ] ) )
+        {
+            eZDebug::writeError( "EnableRSS: content class $currentClassIdentifier is not defined in site.ini[RSSSettings]DefaultFeedItemClasses[<class_id>].", __METHOD__ );
+            return array( 'status' => false );
+        }
+
+        $object = $node->object();
+        $objectID = $object->attribute('id');
+        $currentUserID = eZUser::currentUserID();
+        $rssExportItems = array();
+
+        $db = eZDB::instance();
+        $db->begin();
+
+        $rssExport = eZRSSExport::create( $currentUserID );
+        $rssExport->setAttribute( 'access_url', 'rss_feed_' . $nodeID );
+        $rssExport->setAttribute( 'node_id', $nodeID );
+        $rssExport->setAttribute( 'main_node_only', '1' );
+        $rssExport->setAttribute( 'number_of_objects', $config->variable( 'RSSSettings', 'NumberOfObjectsDefault' ) );
+        $rssExport->setAttribute( 'rss_version', $config->variable( 'RSSSettings', 'DefaultVersion' ) );
+        $rssExport->setAttribute( 'status', eZRSSExport::STATUS_VALID );
+        $rssExport->setAttribute( 'title', $object->name() );
+        $rssExport->store();
+
+        $rssExportID = $rssExport->attribute( 'id' );
+
+        foreach( explode( ';', $feedItemClasses[$currentClassIdentifier] ) as $classIdentifier )
+        {
+            $iniSection = 'RSSSettings_' . $classIdentifier;
+            if ( $config->hasVariable( $iniSection, 'FeedObjectAttributeMap' ) )
+            {
+                $feedObjectAttributeMap = $config->variable( $iniSection, 'FeedObjectAttributeMap' );
+                $subNodesMap = $config->hasVariable( $iniSection, 'Subnodes' ) ? $config->variable( $iniSection, 'Subnodes' ) : array();
+    
+                $rssExportItem = eZRSSExportItem::create( $rssExportID );
+                $rssExportItem->setAttribute( 'class_id', eZContentObjectTreeNode::classIDByIdentifier( $classIdentifier ) );
+                $rssExportItem->setAttribute( 'title', $feedObjectAttributeMap['title'] );
+                if ( isset( $feedObjectAttributeMap['description'] ) )
+                    $rssExportItem->setAttribute( 'description', $feedObjectAttributeMap['description'] );
+        
+                if ( isset( $feedObjectAttributeMap['category'] ) )
+                    $rssExportItem->setAttribute( 'category', $feedObjectAttributeMap['category'] );
+
+                $rssExportItem->setAttribute( 'source_node_id', $nodeID );
+                $rssExportItem->setAttribute( 'status', eZRSSExport::STATUS_VALID );
+                $rssExportItem->setAttribute( 'subnodes', isset( $subNodesMap[$currentClassIdentifier] ) && $subNodesMap[$currentClassIdentifier] === 'true' );
+                $rssExportItem->store();
+            }
+            else
+            {
+                eZDebug::writeError( "site.ini[$iniSection]Source[] setting is not defined.", __METHOD__ );
+            }
+        }
+
+        $db->commit();
+        
+        eZContentCacheManager::clearContentCacheIfNeeded( $objectID );
+
+        return array( 'status' => true );
+    }
+
+    /**
+    * Removes a rss export for a node
+    *
+    * @param int $nodeID Node ID
+    *
+    * @since 4.3
+    **/
+    static public function removeFeedForNode( $nodeID )
+    {
+        $rssExport = eZPersistentObject::fetchObject( eZRSSExport::definition(),
+                                                null,
+                                                array( 'node_id' => $nodeID,
+                                                       'status' => eZRSSExport::STATUS_VALID ),
+                                                true );
+        if ( !$rssExport instanceof eZRSSExport )
+        {
+            eZDebug::writeError( 'DisableRSS: There is no rss feeds left to delete for this node: '. $nodeID, __METHOD__ );
+            return array( 'status' => false );
+        }
+
+        $node = eZContentObjectTreeNode::fetch( $nodeID );
+        if ( !$node instanceof eZContentObjectTreeNode )
+        {
+            eZDebug::writeError( 'DisableRSS: Could not fetch node: '. $nodeID, __METHOD__ );
+            return array( 'status' => false );
+        }
+
+        $objectID = $node->attribute('contentobject_id');
+        $rssExport->removeThis();
+
+        eZContentCacheManager::clearContentCacheIfNeeded( $objectID );
+
+        return array( 'status' => true );
+    }
 }
 ?>
\ No newline at end of file
Index: kernel/content/operation_definition.php
===================================================================
--- kernel/content/operation_definition.php	(revision 24261)
+++ kernel/content/operation_definition.php	(working copy)
@@ -695,4 +695,52 @@
                                                        )
                                                  )
                               );
+
+$OperationList['createnodefeed'] = array( 'name' => 'createnodefeed',
+                                          'default_call_method' => array( 'include_file' => 'kernel/content/ezcontentoperationcollection.php',
+                                          'class' => 'eZContentOperationCollection' ),
+                                'parameter_type' => 'standard',
+                                'parameters' => array(  array( 'name' => 'node_id',
+                                                               'type' => 'integer',
+                                                               'required' => true) ),
+                                'keys' => array( 'node_id' ),
+                                'body' => array( array( 'type' => 'trigger',
+                                                        'name' => 'pre_createnodefeed',
+                                                        'keys' => array( 'node_id' ),
+                                                       ),
+                                                 array( 'type' => 'method',
+                                                        'name' => 'createnodefeed',
+                                                        'frequency' => 'once',
+                                                        'method' => 'createFeedForNode',
+                                                        ),
+                                                 array( 'type' => 'trigger',
+                                                        'name' => 'post_createnodefeed',
+                                                        'keys' => array( 'node_id' )
+                                                       )
+                                                 )
+                              );
+
+$OperationList['removenodefeed'] = array( 'name' => 'removenodefeed',
+                                          'default_call_method' => array( 'include_file' => 'kernel/content/ezcontentoperationcollection.php',
+                                          'class' => 'eZContentOperationCollection' ),
+                                'parameter_type' => 'standard',
+                                'parameters' => array(  array( 'name' => 'node_id',
+                                                               'type' => 'integer',
+                                                               'required' => true) ),
+                                'keys' => array( 'node_id' ),
+                                'body' => array( array( 'type' => 'trigger',
+                                                        'name' => 'pre_removenodefeed',
+                                                        'keys' => array( 'node_id' ),
+                                                       ),
+                                                 array( 'type' => 'method',
+                                                        'name' => 'removenodefeed',
+                                                        'frequency' => 'once',
+                                                        'method' => 'removeFeedForNode',
+                                                        ),
+                                                 array( 'type' => 'trigger',
+                                                        'name' => 'post_removenodefeed',
+                                                        'keys' => array( 'node_id' )
+                                                       )
+                                                 )
+                              );
 ?>
Index: kernel/rss/edit_export.php
===================================================================
--- kernel/rss/edit_export.php	(revision 24261)
+++ kernel/rss/edit_export.php	(working copy)
@@ -99,7 +99,8 @@
     {
         if ( $http->hasPostVariable( 'SourceBrowse_'.$itemCount ) )
         {
-            eZRSSEditFunction::storeRSSExport( $Module, $http );
+            $skipValues = $http->hasPostVariable( 'Ignore_Values_On_Browse_' . $itemCount ) && $http->postVariable( 'Ignore_Values_On_Browse_' . $itemCount );
+            eZRSSEditFunction::storeRSSExport( $Module, $http, false, $skipValues ? $http->postVariable( 'Item_ID_'.$itemCount ) : null );//
             eZContentBrowse::browse( array( 'action_name' => 'RSSObjectBrowse',
                                             'description_template' => 'design:rss/browse_source.tpl',
                                             'from_page' => '/rss/edit_export/'. $RSSExportID .'/'. $http->postVariable( 'Item_ID_'.$itemCount ) .'/NodeSource' ),
@@ -191,6 +192,12 @@
             {
                 $rssExportItem = eZRSSExportItem::fetch( $Params['RSSExportItemID'], true, eZRSSExport::STATUS_DRAFT );
                 $rssExportItem->setAttribute( 'source_node_id', $nodeIDArray[0] );
+                
+                if ( $rssExportItem->attribute('title') == '' && $rssExportItem->attribute('description') == '' )
+                {
+                    eZRSSEditFunction::setItemDefaults( $rssExportItem );
+                }
+
                 $rssExportItem->store();
             }
         } break;
Index: kernel/rss/edit_functions.php
===================================================================
--- kernel/rss/edit_functions.php	(revision 24261)
+++ kernel/rss/edit_functions.php	(working copy)
@@ -36,7 +36,7 @@
      \param HTTP
      \param publish ( true/false )
     */
-    static function storeRSSExport( $Module, $http, $publish = false )
+    static function storeRSSExport( $Module, $http, $publish = false, $skipValuesID = null )
     {
         $valid = true;
         $validationErrors = array();
@@ -61,6 +61,11 @@
         /* Create the new RSS feed */
         for ( $itemCount = 0; $itemCount < $http->postVariable( 'Item_Count' ); $itemCount++ )
         {
+            if ( $skipValuesID == $http->postVariable( 'Item_ID_'.$itemCount ) )
+            {
+                continue;
+            }
+
             $rssExportItem = eZRSSExportItem::fetch( $http->postVariable( 'Item_ID_'.$itemCount ), true, eZRSSExport::STATUS_DRAFT );
             if( $rssExportItem == null )
             {
@@ -175,5 +180,45 @@
                       'published' => $published,
                       'validation_errors' => $validationErrors );
     }
+
+    /**
+     * Set RSSExportItem defaults based on site.ini [RSSSettings] settings
+     * 
+     * @param eZRSSExportItem $rssExportItem
+     * @return bool True if changes where made
+     */
+    static function setItemDefaults( eZRSSExportItem $rssExportItem )
+    {
+        $nodeId = $rssExportItem->attribute( 'source_node_id' );
+        $node = $nodeId ? eZContentObjectTreeNode::fetch( $nodeId ) : null;
+
+        if ( !$node instanceof eZContentObjectTreeNode )
+            return false;
+
+        $config = eZINI::instance( 'site.ini' );
+        $nodeClassIdentifier =  $node->attribute( 'class_identifier' );
+        $defaultFeedItemClasses = $config->variable( 'RSSSettings', 'DefaultFeedItemClasses' );
+        if ( !isset( $defaultFeedItemClasses[$nodeClassIdentifier] ) )
+            return false;
+
+        $feedItemClasses = explode( ';', $defaultFeedItemClasses[$nodeClassIdentifier] );
+        $iniSection = 'RSSSettings_' . $feedItemClasses[0];
+        if ( !$config->hasVariable( $iniSection, 'FeedObjectAttributeMap' ) )
+            return false;
+
+        $feedObjectAttributeMap = $config->variable( $iniSection, 'FeedObjectAttributeMap' );
+        $subNodesMap = $config->hasVariable( $iniSection, 'Subnodes' ) ? $config->variable( $iniSection, 'Subnodes' ) : array();
+
+        $rssExportItem->setAttribute( 'class_id', eZContentObjectTreeNode::classIDByIdentifier( $feedItemClasses[0] ) );
+        $rssExportItem->setAttribute( 'title', $feedObjectAttributeMap['title'] );
+        if ( isset( $feedObjectAttributeMap['description'] ) )
+            $rssExportItem->setAttribute( 'description', $feedObjectAttributeMap['description'] );
+
+        if ( isset( $feedObjectAttributeMap['category'] ) )
+            $rssExportItem->setAttribute( 'category', $feedObjectAttributeMap['category'] );
+
+        $rssExportItem->setAttribute( 'subnodes', isset( $subNodesMap[$nodeClassIdentifier] ) && $subNodesMap[$nodeClassIdentifier] === 'true' );
+        $rssExportItem->store();
+    }
 }
 ?>
\ No newline at end of file
Index: kernel/rss/ezrssfunctioncollection.php
===================================================================
--- kernel/rss/ezrssfunctioncollection.php	(revision 0)
+++ kernel/rss/ezrssfunctioncollection.php	(revision 0)
@@ -0,0 +1,73 @@
+<?php
+//
+// eZRSSFunctionCollection - RSS Function collection
+//
+// Created on: <23-Oct-2009 11:11:54 ar>
+//
+// ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
+// SOFTWARE NAME: eZ Publish
+// SOFTWARE RELEASE: 4.1.x
+// COPYRIGHT NOTICE: Copyright (C) 1999-2009 eZ Systems AS
+// SOFTWARE LICENSE: GNU General Public License v2.0
+// NOTICE: >
+//   This program is free software; you can redistribute it and/or
+//   modify it under the terms of version 2.0  of the GNU General
+//   Public License as published by the Free Software Foundation.
+//
+//   This program is distributed in the hope that it will be useful,
+//   but WITHOUT ANY WARRANTY; without even the implied warranty of
+//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//   GNU General Public License for more details.
+//
+//   You should have received a copy of version 2.0 of the GNU General
+//   Public License along with this program; if not, write to the Free
+//   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+//   MA 02110-1301, USA.
+//
+//
+// ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
+//
+
+class eZRSSFunctionCollection
+{
+    /**
+     * Checks if there is a valid rss export for a node or not.
+     * 
+     * @param int $nodeID
+     * @return bool Return value is inside a array with return value on result, as this is used as template fetch function.
+     */
+    static function hasExportByNode( $nodeID )
+    {
+        if ( !$nodeID )
+            return array( 'error' => array( 'error_type' => 'kernel',
+                                            'error_code' => eZError::KERNEL_NOT_FOUND ) );
+
+        $db = eZDB::instance();
+        $res = $db->arrayQuery( "SELECT id FROM ezrss_export WHERE node_id='$nodeID' AND status=" . eZRSSExport::STATUS_VALID );
+
+        return array( 'result' => isset( $res[0] ) ? true : false );
+    }
+
+    /**
+     * Return valid eZRSSExport object for a specific node if it exists.
+     * 
+     * @param int $nodeID
+     * @return eZRSSExport|false Return value is inside a array with return value on result, as this is used as template fetch function.
+     */
+    static function exportByNode( $nodeID )
+    {
+        if ( !$nodeID )
+            return array( 'error' => array( 'error_type' => 'kernel',
+                                            'error_code' => eZError::KERNEL_NOT_FOUND ) );
+
+        $rssExport = eZPersistentObject::fetchObject( eZRSSExport::definition(),
+                                                null,
+                                                array( 'node_id' => $nodeID,
+                                                       'status' => eZRSSExport::STATUS_VALID ),
+                                                true );
+
+        return array( 'result' => $rssExport );
+    }
+}
+
+?>
\ No newline at end of file

Property changes on: kernel\rss\ezrssfunctioncollection.php
___________________________________________________________________
Added: svn:eol-style
   + native

Index: kernel/rss/function_definition.php
===================================================================
--- kernel/rss/function_definition.php	(revision 0)
+++ kernel/rss/function_definition.php	(revision 0)
@@ -0,0 +1,21 @@
+<?php
+
+$FunctionList = array();
+
+$FunctionList['has_export_by_node'] = array( 'name' => 'has_node_map',
+                               'operation_types' => array( 'read' ),
+                               'call_method' => array( 'class' => 'eZRSSFunctionCollection',
+                                                       'method' => 'hasExportByNode' ),
+                               'parameter_type' => 'standard',
+                               'parameters' => array( array( 'name' => 'node_id',
+                                                             'type' => 'integer',
+                                                             'required' => true ) ) );
+$FunctionList['export_by_node'] = array( 'name' => 'node_map',
+                                   'operation_types' => array( 'read' ),
+                                   'call_method' => array( 'class' => 'eZRSSFunctionCollection',
+                                                           'method' => 'exportByNode' ),
+                                   'parameter_type' => 'standard',
+                                   'parameters' => array( array( 'name' => 'node_id',
+                                                                 'type' => 'integer',
+                                                                 'required' => true ) ) );
+?>
\ No newline at end of file

Property changes on: kernel\rss\function_definition.php
___________________________________________________________________
Added: svn:eol-style
   + native

Index: settings/site.ini
===================================================================
--- settings/site.ini	(revision 24261)
+++ settings/site.ini	(working copy)
@@ -1150,7 +1150,30 @@
 AvailableVersionList[]=2.0
 AvailableVersionList[]=ATOM
 # Selected by default in the RSS export edit GUI.
-DefaultVersion=1.0
+DefaultVersion=2.0
+
+# Default source to child mapping
+# DefaultFeedItemClasses[<source_class>]=<child_class>[;<child_class_2>]
+DefaultFeedItemClasses[]
+#eq: DefaultFeedItemClasses[folder]=article
+
+## Default class attribute to rss attribute mapping
+#[RSSSettings_<class_identifier>]
+## Requried to be able to map title attribute
+#FeedObjectAttributeMap[title]=<class_attribute_identifier>
+## Optional to map description field
+#FeedObjectAttributeMap[description]=<class_attribute_identifier>
+## Optional to map category field
+#FeedObjectAttributeMap[category]=<class_attribute_identifier>
+## Optional to fetch subtree of these items
+#Subnodes[<source_class_identifier>]=true
+
+# Eg:
+#[RSSSettings_article]
+#FeedObjectAttributeMap[title]=title
+#FeedObjectAttributeMap[description]=intro
+#FeedObjectAttributeMap[category]=tags
+
 
 [BackwardCompatibilitySettings]
 # Enables or disables compatibility with admin design from
Index: settings/workflow.ini
===================================================================
--- settings/workflow.ini	(revision 24261)
+++ settings/workflow.ini	(working copy)
@@ -54,6 +54,8 @@
 # AvailableOperationList[]=content_updatealwaysavailable
 # AvailableOperationList[]=content_removetranslation
 # AvailableOperationList[]=content_updateobjectstate
+# AvailableOperationList[]=content_createnodefeed
+# AvailableOperationList[]=content_removenodefeed
 # AvailableOperationList[]=user_activation
 # AvailableOperationList[]=user_password
 # AvailableOperationList[]=user_forgotpassword
